diff --git a/.gitignore b/.gitignore
index 2873e189e1..4846138ac2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,7 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+/data/
+
+.vscode/
+text-ui-test/data/
\ No newline at end of file
diff --git a/README.md b/README.md
index f82e2494b7..5e261abbce 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1,37 @@
-# Duke project template
-
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
-
-## Setting up in Intellij
-
-Prerequisites: JDK 11 (use the exact version), update Intellij to the most recent version.
-
-1. **Ensure Intellij JDK 11 is defined as an SDK**, as described [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk) -- this step is not needed if you have used JDK 11 in a previous Intellij project.
-1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html).
-1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
- ```
- > Task :compileJava
- > Task :processResources NO-SOURCE
- > Task :classes
-
- > Task :Duke.main()
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
-
- What is your name?
- ```
- Type some word and press enter to let the execution proceed to the end.
-
-## Build automation using Gradle
-
-* This project uses Gradle for build automation and dependency management. It includes a basic build script as well (i.e. the `build.gradle` file).
-* If you are new to Gradle, refer to the [Gradle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/gradle.html).
-
-## Testing
-
-### I/O redirection tests
-
-* To run _I/O redirection_ tests (aka _Text UI tests_), navigate to the `text-ui-test` and run the `runtest(.bat/.sh)` script.
-
-### JUnit tests
-
-* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template.
-* If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html).
-
-## Checkstyle
-
-* A sample CheckStyle rule configuration is provided in this project.
-* If you are new to Checkstyle, refer to the [Checkstyle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/checkstyle.html).
-
-## CI using GitHub Actions
-
-The project uses [GitHub actions](https://github.com/features/actions) for CI. When you push a commit to this repo or PR against it, GitHub actions will run automatically to build and verify the code as updated by the commit/PR.
-
-## Documentation
-
-`/docs` folder contains a skeleton version of the project documentation.
-
-Steps for publishing documentation to the public:
-1. If you are using this project template for an individual project, go your fork on GitHub.
- If you are using this project template for a team project, go to the team fork on GitHub.
-1. Click on the `settings` tab.
-1. Scroll down to the `GitHub Pages` section.
-1. Set the `source` as `master branch /docs folder`.
-1. Optionally, use the `choose a theme` button to choose a theme for your documentation.
+
+
AthletiCLI
+
+ Your all-in-one solution to track, analyse, and optimize your athletic performance.
+
+
+**AthletiCLI** is your all-in-one solution to track, analyse, and optimize your athletic performance. Designed for the committed athlete, this command-line interface (CLI) tool not only keeps tabs on your physical activities but also covers dietary habits, sleep metrics, and more.
+
+* If you are interested in using AthletiCLI, head over to the [:green_book: User Guide](UserGuide.html).
+* If you are interested about developing AthletiCLI, the [:blue_book: Developer Guide](DeveloperGuide.html) is a good place to start.
+* If you would like to learn more about our development team, please visit the [:orange_book: About Us](AboutUs.html) page.
+
+
+
+## :rocket: Quick Start
+
+* :white_check_mark: Ensure you have the required runtime environment (JRE 11 or above) installed on your computer.
+* :white_check_mark: Download the latest [release](https://github.com/AY2324S1-CS2113-T17-1/tp/releases) of AthletiCLI.
+* :white_check_mark: Copy the downloaded file to a folder you want to designate as the home for AthletiCLI.
+* :white_check_mark: Open a command terminal, `cd` into the folder where you copied the file, and run `java -jar AthletiCLI.jar` .
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index ea82051fab..20ce57b54d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,11 +29,11 @@ test {
}
application {
- mainClass.set("seedu.duke.Duke")
+ mainClass.set("athleticli.AthletiCLI")
}
shadowJar {
- archiveBaseName.set("duke")
+ archiveBaseName.set("athleticli")
archiveClassifier.set("")
}
@@ -43,4 +43,5 @@ checkstyle {
run{
standardInput = System.in
+ enableAssertions = true
}
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000000..818ff30bce
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,2 @@
+Gemfile.lock
+_site/
\ No newline at end of file
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..76199580b4 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,18 @@
-# About us
+---
+layout: page
+title: About Us
+---
-Display | Name | Github Profile | Portfolio
---------|:----:|:--------------:|:---------:
-![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
-![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+
+
+| Display | Name | GitHub Profile | Portfolio |
+|:----------------------------------------------:|:-----------------:|:----------------------------------------:|:----------------------------------:|
+| ![](https://github.com/AlWo223.png) | Alexander Wolters | [GitHub](https://github.com/AlWo223) | [Portfolio](team/alwo223.html) |
+| ![](https://github.com/nihalzp.png) | Nihal Parash | [GitHub](https://github.com/nihalzp) | [Portfolio](team/nihalzp.html) |
+| ![](https://github.com/DaDevChia.png) | Dylan Chia | [GitHub](https://github.com/DaDevChia) | [Portfolio](team/dadevchia.html) |
+| ![](./team/photo/yicheng-toh.png) | Toh Yi Cheng | [GitHub](https://github.com/yicheng-toh) | [Portfolio](team/yicheng-toh.html) |
+| ![](https://github.com/skylee03.png) | Yang Ming-Tian | [GitHub](https://github.com/skylee03) | [Portfolio](team/skylee03.html) |
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..902e2fba25 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,38 +1,784 @@
-# Developer Guide
+---
+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}
+[//]: # ({list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well})
+
+1. [AB-3 Developer Guide](https://se-education.org/addressbook-level3/DeveloperGuide.html)
+2. [PlantUML for sequence diagrams](https://plantuml.com/)
+
+---
+## Setting Up and Getting Started
+
+First, fork [this repo](https://github.com/AY2324S1-CS2113-T17-1/tp), and clone the fork into your computer.
+
+If you plan to use IntelliJ IDEA (highly recommended):
+
+1. **Configure the JDK**: Follow the guide [se-edu/guides IDEA: Configuring the JDK](https://se-education.org/guides/tutorials/intellijJdk.html) to ensure IntelliJ is configured to use JDK 11.
+2. **Import the project as a Gradle project**: Follow the guide
+[se-edu/guides IDEA: Importing a Gradle project](https://se-education.org/guides/tutorials/intellijImportGradleProject.html)
+to import the project into IDEA.
+
+ :exclamation: **Note:** Importing a Gradle project is slightly different from importing a normal Java project.
+3. **Verify the setup**:
+ * Run `athlethicli.AthletiCLI` and try a few commands.
+ * Run the tests using `./gradlew check` and ensure they all pass.
+
+
+
+
+---
+## Design
+
+This section provides a high-level explanation of the design and implementation of AthletiCLI,
+supported by UML diagrams and short code snippets to illustrate the flow of data and interactions between the
+components.
+
+---
+### Architecture
+
+Given below is a quick overview of main components and how they interact with each other.
+
+
+
+**Main components of the architecture**
+
+[`AthletiCLI`](https://github.com/AY2324S1-CS2113-T17-1/tp/blob/master/src/main/java/athleticli/AthletiCLI.java) is in charge of the app launch and shut down.
+
+The bulk of the AthletiCLI’s work is done by the following components, with each of them corresponds to a package:
+
+* [`Ui`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/ui): Interacts with the user via the command line.
+* [`Parser`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/parser): Parses the commands input by the users.
+* [`Storage`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/storage): Reads data from, and writes data to, the hard disk.
+* [`Data`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/data): Holds the data of AthletiCLI in memory.
+* [`Commands`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/commands): Contains multiple command executors.
+
+Other components:
+
+* [`Exceptions`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/exceptions): Represents exceptions used by multiple other components.
+* [`Common`](https://github.com/AY2324S1-CS2113-T17-1/tp/tree/master/src/main/java/athleticli/common): Contains configurations that shared by other components.
+
+### Overview
+
+The class diagram shows the relationship between `AthletiCLI`, `Ui`, `Parser`, and `Data`.
+
+![](images/MainClassDiagram.svg)
+
+### Data Component
+
+The class diagram shows how the `Data` component is constructed with multiple classes.
+
+![](images/DataClassDiagram.svg)
+
+### Parser Component
+
+The class diagram shows how the `Parser` component is constructed with multiple classes.
+
+![](images/ParserClassDiagram.png)
+
+**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 `help add-diet`.
+
+![](images/HelpAddDiet.svg)
+
+This diagram involves the interaction between `AthletiCLI`, `Ui`, `Parser`, `Commands` components and the user.
+
+The `Storage` component only interacts with the `Data` component. The _Sequence Diagram_ below shows how they interact with each other for the scenario where a `save` command is executed.
+
+![](images/Save.svg)
+
+For simplicity, only 1 `StorableList` is drawn instead of the actual 6.
+
+---
+
+## Implementation
+
+### Diet Management in AthletiCLI
+
+#### [Implemented] Adding, Editing, Deleting, Listing, and Finding Diets
+
+Regardless of the operation you are performing on diets (adding, editing, deleting, listing, or finding), the process
+follows a general five-step pattern in AthletiCLI:
+
+**Step 1 - Input Processing:** The user's input is passed through AthletiCLI to the `Parser` class. Examples of user
+inputs include:
+
+- `add-diet calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` for adding a diet.
+- `edit-diet 1 calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` for editing a diet at index 1.
+- `delete-diet 1` for deleting a diet at index 1.
+- `list-diet` for listing all diets.
+- `find-diet 2021-09-01` for finding all diets on 1st September 2021.
+
+**Step 2 - Command Identification:** The `Parser` class identifies the type of diet operation and calls the
+appropriate `DietParser` method to parse the necessary parameters (if any). For example, the `add-diet` command will
+call the `DietParser#parseDiet()` method, which will return a `Diet` object.
+
+**Step 3 - Command Creation**: An instance of the corresponding command class is created (e.g., `AddDietCommand`,
+`EditDietCommand`, etc.) using the returned object (if any) from the `DietParser` and returned to AthletiCLI.
+
+**Step 4 - Command Execution**: AthletiCLI executes the command, interacting with the data instance of DietList to
+perform the required operation. For example, the `AddDietCommand` will add the `Diet` object to the `DietList` object,
+while the `EditDietCommand` will edit the `Diet` object at the specified index in the `DietList` object.
+
+**Step 5 - Result Display**: A message is returned post-execution and passed through AthletiCLI to the UI for
+display to the user. This is useful for informing the user of the success or failure of the operation.
+
+By following these general steps, AthletiCLI ensures a streamlined process for managing diet-related tasks.
+
+Here is the sequence diagram for the `edit-diet` command to illustrate the five-step process:
+
+![](images/editDietSequenceDiagram.png)
+
+> The diagram shows the interaction between the `AthletiCLI`, `Parser`, `Command`, and `Data` components.
+> The use of HashMaps in the `DietParser` class allows for a more flexible and extensible design, as it facilitates
+> the modification of necessary parameters without requiring the user to specify all parameters in the command. For
+> example, the user can choose to edit only the calories and protein of a diet, without specifying the carb and fat values.
+
+
+#### [Implemented] Setting Up of Diet Goals
+
+This following sequence diagram show how the 'set-diet-goal' command works:
+
+![](images/DietGoalsSequenceDiagram.svg)
+
+**Step 1:** The input from the user ("set-diet-goal WEEKLY fat/1") runs through AthletiCLI to the Parser Class.
+
+**Step 2:** The Parser Class will identify the request as setting up a diet goal and pass in the parameters
+"WEEKLY fat/1".
+
+**Step 3:** A temporary dietGoalList is created to store newly created diet goals. In this case, a weekly healthy goal
+for fat with a target value of 1mg.
+
+**Step 4:** The inputs are validated against our lists of approved diet goals.
+
+**Step 5:** For each of the diet goals that are valid, if it is a healthy goal, a HealthyDietGoal object will be created and stored in the
+temporary dietGoalList, else an UnhealthyDietGoal will be created instead.
+
+**Step 6:** The Parser then creates for an instance of SetDietGoalCommand and returns the instance to
+AthletiCLI.
+
+**Step 7:** AthletiCLI will execute the SetDietGoalCommand. This adds the dietGoals that are present in the
+temporary list into the data instance of DietGoalList which will be kept for records.
+
+**Step 8:** After executing the SetDietGoalCommand, SetDietGoalCommand returns a message that is passed to
+AthletiCLI to be passed to UI(not shown) for display.
+
+#### [Proposed] Future Implementation of DietGoalList Class
+
+The current implementation of DietGoalList is an ArrayList. This is because the number of nutrients currently is 4. O(n^2)
+operations can be treated as O(1). Furthermore, DietGoalListClass gets to inherits from superclass like its other goals' counterpart.
+However, it is not efficient in searching for a particular dietGoal especially when the number of goals and time span for goals increases.
+At any instance of time, there could only be the existence of one dietGoal.
+Verifying if there is an existence of a diet goal using an ArrayList takes O(n) time, where n is the number of dietGoals.
+The proposed change will be to change the underlying data structure to a hashmap in the future for amortised O(1) time complexity
+for checking the presence of a dietGoal.
+
+### Activity Management in AthletiCLI
+
+#### [Implemented] Adding activities
+
+The `add-activity` feature is a core functionality which allows users to record new activities in the application.
+The feature is designed in a modular and extendable way, ensuring seamless integration of future enhancements and
+especially new activity types.
+
+The architecture of the `add-activity` feature is composed of the following main components.
+1. `AthletiCLI`: Facilitates the mechanism. It captures the user input and initiates the parsing and execution.
+2. `Parser` (`Activity Parser`): Interprets the user input, generating both the appropriate command object and
+ the activity instance.
+3. `AddActivityCommand`: Encapsulates the execution of the `add-activity` command, adding the activity to the data.
+4. `ActivityChanges`: Contains the arguments of the activity to be added. It is used to transfer the data from the
+ parser to the activity in a modular way.
+5. `Activity`: Represents the activity to be added. It is a superclass for specific activity types like Run, Swim and
+ Cycle.
+6. `Data`: Manages the current state of the activity list.
+7. `ActivityList`: Maintains the list of all activities added to the application.
+
+
+Class Relationships:
+
+Below is a class diagram illustrating the relationships between the data components `Activity`,`Data` and
+`ActivityList`:
+
+
+
+> The diagram shows the inheritance relationship between the `Activity` class and the specific activity types `Run`,
+> `Swim` and `Cycle`, each with unique attributes and methods. This design becomes especially crucial in future
+> development cycles with added parameters and activity types. The `ActivityList` aggregates these instances.
+
+Usage Scenario and Process Flow:
+
+The process of adding an activity involves several steps, each handled by different components.
+Given below is an example usage scenario on how the add mechanism behaves.
+
+**Step 1 - Input Capture:** The user issues an `add-activity ...` (or `add-run`, etc.) command which is
+captured and forwarded to the Parser by the running AthletiCLI instance.
+
+**Step 2 - Activity Parsing:** The ActivityParser interprets the raw input to obtain the arguments of the activity.
+Given that all parameters are provided correctly and no exception is thrown, a new activity object is created.
+
+This diagram illustrates the activity parsing process in more detail:
+The `ActivityChanges` object plays a key role in the parsing process. It is used for storing the
+different attributes of the activity that are to be added. Later, the `ActivityParser`
+will use the `ActivityChanges` to create the `Activity` object.
+> This way of transferring data between the parser and the activity is more flexible which is suitable for future
+> extensions of the activity types and allows for a more modular design. This design and most of the methods can be reused
+> for the `edit-activity` mechanism, which works in the same way with slight modifications due to optional parameters.
+
+
+
+
+
+**Step 3 - Command Parsing:** Afterwards the parser constructs an `AddActivityCommand` embedding the newly created
+activity within it. The `AddActivityCommand` implements the `AddActivityCommand#execute()` operation and is passed to
+the AthletiCLI instance.
+
+**Step 4 - Activity Addition:** The AthletiCLI instance executes the `AddActivityCommand` object. The command
+accesses the data and retrieves the currently stored list of activities stored inside it. The new `Activity` object is
+then added to the `ActivityList`.
+
+**Step 5 - User Interaction:** Upon successful addition of the activity, a confirmation message is displayed to the
+user.
+
+The following sequence diagram visually represents the flow and interactions of components during the `add-activity`
+operation:
+
+![](images/AddActivity.svg)
+
+#### [Implemented] Tracking activity goals
+
+The `set-activity-goal` feature allows users to set and track periodic goals for their activities.
+The goal fulfillment is automatically monitored and can be reviewed by the user at any time.
-## Design & implementation
+These are the key components and their roles in the architecture of the goal tracking:
+* `SetActivityGoalCommand`: Encapsulates the execution of the `set-activity-goal` command. It adds
+ the activity goal to the data.
+* `ActivityGoal`: Represents the activity goal that is to be added and contains functionality to
+ track the fulfillment of the goal.
+* `ActivityList`: Contains key functionality to retrieve and filter the activity list according to the specified
+ criteria of the goal.
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+Given below is an example usage scenario and how the goal setting and tracking mechanism behaves at
+each step.
+**Step 1 - Input Capture:** The user issues a `set-activity-goal ...` command which is captured and passed to the
+ Parser by the running AthletiCLI instance.
+
+**Step 2 - Goal Parsing:** The `ActivityParser` parses the raw input to obtain the sports, target and timespan of the
+ goal.
+ Given that all these parameters are provided correctly and no exception is thrown, a new activity goal object is
+ created.
+
+**Step 3 - Command Parsing:** In addition the parser will create a `SetActivityGoalCommand` object with the newly
+ added activity goal attached to it. The command implements the `SetActivityGoalCommand#execute()` operation and is
+ passed to the AthletiCLI instance.
+
+**Step 4 - Goal Addition:** The AthletiCLI instance executes the `SetActivityGoalCommand` object. The command will
+ access the data and retrieve the currently stored list of activity goals stored inside it. The new `ActivityGoal`
+ object is added to the list.
+
+The following sequence diagram shows how the `set-activity-goal` operation works:
+
+![](images/AddActivityGoal.svg)
+
+Assume that the user has set a goal to run 10km per week and has already tracked two running activities of 5km each
+within the last 7 days as well as three older sport activities. The object diagram below shows the state of the
+scenario with the eligible activities for the goal highlighted in green.
+
+![](images/ActivityObjectDiagram.svg)
+
+The following describes how the goal evaluation works after being invoked by the user, e.g., with a `list-activity-goal` command:
+
+**Step 5 - Goal Assessment:** The evaluation of the goal is operated by the `ActivityGoal` object. It retrieves the
+activity list with the five tracked activities from the data and calls the total distance calculation function. It
+ filters the activity list according to the specified timespan and sports of the goal. The current value obtained by this,
+ 10km in the example, is returned to the `ActivityGoal` object. This output is compared to the target value of the
+ goal. This mechanism is visualized in the following sequence diagram:
+
+![](images/ActivityGoalEvaluation.svg)
+
+The `edit-activity-goal` and `delete-activity-goal` operations function similarly. They use the arguments `sport`,
+`type`, and `period` to identify the specific goal to be edited or deleted. If there is no existing goal that
+matches the specified criteria, an error message is displayed to the user.
+
+Similar to `set-activity-goal`, the operations `edit-activity-goal` and `delete-activity-goal` utilize
+`ActivityGoal` objects to represent the goals being edited or deleted. During the execution of these commands, the
+system quickly verifies whether the goal exists in the `ActivityGoalList`. If the goal is found, it is then edited
+or deleted as requested.
+
+Finally, the `list-activity-goal` operation is designed similarly to the `list-activity` operation. It involves
+retrieving the `ActivityGoalList` from the database and displaying the goals to the user.
+
+### Sleep Management in AthletiCLI
+
+#### [Implemented] Finding, Adding, Editing, Deleting, Listing Sleep
+
+1. **Input Processing**: The user's input is passed through AthletiCLI to the Parser Class. Examples of user inputs include:
+ - "add-sleep hours/8 datetime/2021-09-01 06:00" for adding sleep.
+ - "edit-sleep 1 hours/8 datetime/2021-09-01 06:00" for editing sleep.
+ - "delete-sleep 1" for deleting sleep.
+ - "list-sleep" for listing all sleep.
+
+2. **Command Identification**: The Parser Class identifies the type of sleep operation and passes the necessary parameters.
+
+3. **Command Creation**: An instance of the corresponding command class is created (e.g., AddSleepCommand, EditSleepCommand, etc.) and returned to AthletiCLI.
+
+4. **Command Execution**: AthletiCLI executes the command, interacting with the data instance of SleepList to perform the required operation.
+
+5. **Result Display**: A message is returned post-execution and passed through AthletiCLI to the UI for display to the user.
+
+In particular to demonstrate all parser classes, the following sequence diagram shows how the `edit-sleep` command works:
+
+![](images/EditSleepObjectSequenceDiagram.svg)
+
+The sleep parser was originally designed with little modularity, with each sleep instruction having to be parsed individually. This resulted in a lot of code duplication and was not very modular. This also resulted in having to reimplement much of the input checking logic for each sleep instruction, and many different error messages that was difficult to maintain.
+
+Therefore a refactoring was done such that we only have a sleep object parser, sleep index parser and sleep goal parser that interacts with the sleep parser. This allows us to reuse the input checking logic and error messages. This also allows us to have a more modular design and reduce code duplication.
+
+
+#### [Implemented] Sleep Structure
+
+The following class diagram demonstrates the relationship between the data components Sleep, SleepList, as well as the Findable interface and the StorableList abstract class.
+
+![](images/SleepAndSleepListClassDiagram.svg)
+
+The design decision for why we have decided to implement a findable interface and a storable list abstract class is to have a more modular design. Therefore allowing for easier extension of the code in the future when implementing other data classes as well, such as extending to hydration and other possible data classes.
+
+#### [Implemented] Sleep Duration and Date calculation
+
+Initially sleep entries do not have an associated date, this makes it much more difficult to find the sleep entries for a specific date. Therefore we have decided to add a date field to the sleep entries.
+
+However, there are complications surrounding calculation of sleep date. Many people often sleep past midnight, and this results in the sleep date being the next day instead of the current day. Therefore we have decided that for sleeps starting before 06:00 on the next day, the sleep date will be the previous day. This allows us to have a more accurate representation of the sleep date.
+
+**[Challenge]**
+
+Initially, the design of the sleep duration used integer to store the seconds of the sleep duration. However, this design results in much difficulty when it comes to the calculation of the sleep duration.
+
+For instance, when printing the sleep duration string, we have to convert the seconds into hours, minutes and seconds. This results in a lot of code duplication and is not very modular.
+
+**[Solution]**
+
+Therefore we have decided to change the design of the sleep duration to use the Duration class from the Java library. This allows us to use the built-in functions to calculate the sleep duration and convert the sleep duration into a string. This results in a more modular design and reduces code duplication.
+
+#### [Implemented] Sleep Goals
+
+The sleep goals feature allows users to set and track periodic goals for their sleep duration.
+
+The implementation of sleep goals is similar to the implementation of activity goals. Therefore the implementation of sleep goals is not described in detail here.
+
+**[Future Implementation]**
+For Sleep Goals originally there were plans to incorporate a sleep quality goal where an optimum sleep start time and end time would be set. However, due to issues surrounding modular design, and how we will have to extend our common Goal interface and abstract classes to include more methods, we have decided to not implement this feature. It will be implemented in a future version of AthletiCLI.
+
+---
## Product scope
+
### Target user profile
-{Describe the target user profile}
+AthletiCLI is designed for athletic individuals who are committed to optimizing their performance.
+
+These users are highly disciplined and engaged not only in regular, intense physical training but also in nutrition, mental conditioning, and recovery.
+
+They are looking for a holistic tool that integrates all facets of an athletic lifestyle. AthletiCLI serves as a daily or weekly companion, designed to monitor, track, and analyze various elements crucial for high-level athletic performance.
### Value proposition
-{Describe the value proposition: what problem does it solve?}
+AthletiCLI provides a streamlined, integrated solution for athletic individuals focused on achieving peak performance.
+
+While the app includes robust capabilities for tracking physical training metrics, it also offers features for monitoring dietary habits and sleep metrics.
+
+By providing a comprehensive view of various performance-related factors over time, AthletiCLI enables athletes to identify trends, refine their training and lifestyle habits, and optimize outcomes. The app is more than a tracking tool—it's a performance optimization platform that takes into account the full spectrum of an athlete's life.
+
+---
## User Stories
-|Version| As a ... | I want to ... | So that I can ...|
-|--------|----------|---------------|------------------|
-|v1.0|new user|see usage instructions|refer to them when I forget how to use the application|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+
+| Version | As a ... | I want to ... | So that I can ... |
+|---------|---------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------|
+| v1.0 | fitness enthusiastic user | add different activities including running, swimming and cycling) | keep track of my fitness activities and athletic performance. |
+| v1.0 | analytical user | view my activity details at any point in time | track my progress and make informed decisions about my fitness routine. |
+| v1.0 | clumsy user | delete any tracked activity | I can correct any mistakes or remove accidentally added activities. |
+| v1.0 | detail-oriented user | modify any of my tracked activities | ensure accuracy in my fitness records. |
+| v1.0 | health-conscious user | add my dietary information | keep track of my daily calorie and nutrient intake |
+| v1.0 | organized user | delete a dietary entry | remove outdated or incorrect data from my diet records |
+| v1.0 | fitness enthusiast | view all my diet records | have a clear overview of my dietary habits and make informed decisions on my diet |
+| v1.0 | new user | see usage instructions | refer to them when I forget how to use the application |
+| v1.0 | motivated weight-conscious user | set diet goals | have the motivation to work towards keeping weight in check. |
+| v1.0 | forgetful user | see all my diet goals | remind myself of all the diet goals I have set. |
+| v1.0 | regretful user | remove my diet goals | I can rescind the strict goals I set previously when I find the goals too far fetched. |
+| v1.0 | motivated user | update my diet goals | I can work towards better version of myself by setting stricter goals. |
+| v1.0 | sleep deprived user | add my sleep information | keep track of my sleep habits and identify areas for improvement |
+| v1.0 | sleep deprived user | delete a sleep entry | remove outdated or incorrect data from my sleep records |
+| v1.0 | sleep deprived user | view all my sleep records | have a clear overview of my sleep habits and make informed decisions on my sleep |
+| v1.0 | sleep deprived user | edit my sleep entries | correct any mistakes or update my sleep information as needed |
+| v2.0 | user | find a to-do item by name | locate a to-do without having to go through the entire list |
+| v2.0 | meticulous user | edit my dietary entries | correct any mistakes or update my diet information as needed |
+| v2.0 | active user | set activity goals | work towards a specific fitness target for different sports activities. |
+| v2.0 | adaptable athlete | edit my activity goals | modify my fitness targets to align with my current fitness level and schedule. |
+| v2.0 | organized athlete | list all my activity goals | have a clear overview of my set targets and track my progress easily. |
+| v2.0 | meticulous user | find my diets by date | easily retrieve my dietary records for a specific day and monitor my eating habits. |
+| v2.0 | motivated user | keep track of my diet goals for a period of time | I can monitor my diet progress on a weekly basis and increase or reduce if needed. | |
+| v2.0 | goal-oriented user | delete a specific activity goal | remove goals that are no longer relevant or achievable for me. | |
+| v2.0 | sleep deprived user | calculate sleep duration | keep track of my sleep habits and identify areas for improvement |
+| v2.0 | sleep deprived user | find how much I slept on a specific date | easily retrieve my sleep records for a specific day and monitor my sleep habits. |
+| v2.1 | user with bad sleep habits | set sleep goals | work towards a specific sleep target. |
+| v2.1 | user with bad sleep habits | edit my sleep goals | modify my sleep targets to align with my current sleep habits. |
+| v2.1 | user with bad sleep habits | list all my sleep goals | have a clear overview of my set targets and track my progress easily. |
+
+---
## Non-Functional Requirements
-{Give non-functional requirements}
+1. AthletiCLI should work on Windows, macOS and Linux that has Java 11 installed.
+2. AthletiCLI should be able to store data locally.
+3. AthletiCLI should be able to work offline.
+4. AthletiCLI should be easy to use.
+
+---
## Glossary
-* *glossary item* - Definition
+[//]: # (* *glossary item* - Definition)
+* **UI** - A short form for User Interface. A UI class refers to the class that is responsible for handling user input
+and provide feedback to the users.
+
+
+---
## Instructions for manual testing
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+**Note**: This section serves to provide a quick start for manual testing on AthletiCLI. This list is not exhaustive.
+Developers are expected to conduct more extensive tests.
+
+### Initial Launch
+
+* ✅ Download the latest AthletiCLI from the official repository.
+* ✅ Copy the downloaded file to a folder you want to designate as the home for AthletiCLI.
+* ✅ Open a command terminal, cd into the folder where you copied the file, and run `java -jar AthletiCLI.jar`.
+
+### Activity Management
+
+#### Activity Records
+
+1. Adding different activities:
+ - Test case 1:
+ * Add a general activity.
+ * Command: `add-activity Morning Run duration/01:00:00 distance/10000 datetime/2021-09-01 06:00`
+ * Expected Outcome: A general activity with duration of 1 hour, distance of 10km, and datetime of 2021-09-01 is
+ added successfully and a short summary of the activity is displayed to the user.
+ - Test case 2:
+ * Add a run.
+ * Command: `add-run Berlin Marathon duration/03:33:17 distance/42125 datetime/2023-08-10 07:00 elevation/10`
+ * Expected Outcome: A run with duration of 3 hours 33 minutes 17 seconds, distance of 42.125km, datetime of
+ 2023-08-10, and elevation of 10m is added successfully and a short summary of the activity is displayed to
+ the user.
+ - Test case 3:
+ * Try to add a swim without specifying swimming style.
+ * Command: `add-swim Evening Swim duration/00:30:00 distance/1000 datetime/2021-09-01 06:00`
+ * Expected Outcome: Error message indicating the swimming style is not specified is displayed.
+2. Deleting an activity:
+ - Test case 1:
+ * Delete the first activity in a non-empty activity list.
+ * Command: `delete-activity 1`
+ * Expected Outcome: The first activity is deleted successfully. The activity is displayed to the user and
+ the activity list is updated.
+ - Test case 2:
+ * Delete an activity at an invalid index.
+ * Command: `delete-activity 0`
+ * Expected Outcome: Error message indicating the index is invalid is displayed.
+3. List all activities:
+ - Test case 1:
+ * List all activities in a non-empty activity list.
+ * Command: `list-activity`
+ * Expected Outcome: All activities in the activity list are displayed to the user sorted by datetime.
+ - Test case 2:
+ * List all activities in a non-empty activity list with the detailed flag.
+ * Command: `list-activity -d`
+ * Expected Outcome: All activities in the activity list are displayed to the user with detailed information
+ like elevation for runs and cycles.
+ - Test case 2:
+ * List all activities in an empty activity list.
+ * Command: `list-activity`
+ * Expected Outcome: Message indicating the activity list is empty is displayed.
+4. Find activities of a specific date:
+ - Test case 1:
+ * Find activities of a specific date with multiple entries on that date.
+ * Command: `find-activity 2021-09-01`
+ * Expected Outcome: All activities on 1st September 2021 are displayed to the user.
+ - Test case 2:
+ * Find activities of a specific date with no entries on that date.
+ * Command: `find-activity 2021-09-02`
+ * Expected Outcome: No activities are displayed
+5. Edit an activity:
+ - Test case 1:
+ * Edit the caption of the first activity in the activity list, which is of type run.
+ * Command: `edit-run 1 caption/Sunday=Runday`
+ * Expected Outcome: The caption of the first activity is updated to "Sunday=Runday".
+ - Test case 2:
+ * Try to use the edit-swim command to edit a run.
+ * Command: `edit-swim 1 caption/Sunday=Runday`
+ * Expected Outcome: Error message indicating the activity type is not a swim is displayed.
+
+#### Activity Goals
+
+1. Setting Activity Goals
+ - Test case 1:
+ * Set a weekly running distance goal.
+ * Command: `set-activity-goal sport/running type/distance period/weekly target/15000`
+ * Expected Outcome: Weekly running goal of 15km is set successfully.
+ - Test case 2:
+ * Set a monthly swimming duration goal.
+ * Command: `set-activity-goal sport/swimming type/duration period/monthly target/300`
+ * Expected Outcome: Monthly swimming duration goal of 300 minutes is set successfully.
+
+2. Editing Activity Goals
+ - Test case 1:
+ * Edit an existing weekly cycling distance goal.
+ * Command: `edit-activity-goal sport/cycling type/distance period/weekly target/20000`
+ * Expected Outcome: Weekly cycling distance goal is updated to 20km.
+ - Test case 2:
+ * Edit a non-existent yearly running duration goal.
+ * Command: `edit-activity-goal sport/running type/duration period/yearly target/1000`
+ * Expected Outcome: Error indicating no existing yearly running duration goal.
+
+3. Listing Activity Goals
+ - Test case 1:
+ * List all set activity goals.
+ * Command: `list-activity-goal`
+ * Expected Outcome: All set activity goals along with their details are listed.
+
+4. Deleting Activity Goals
+ - Test case 1:
+ * Delete an existing monthly swimming duration goal.
+ * Command: `delete-activity-goal sport/swimming type/duration period/monthly`
+ * Expected Outcome: Monthly swimming duration goal is deleted successfully.
+ - Test case 2:
+ * Attempt to delete a non-existent daily general activity goal.
+ * Command: `delete-activity-goal sport/general type/distance period/daily`
+ * Expected Outcome: Error indicating no such daily general activity goal exists.
+
+### Diet Management
+
+#### Diet Records
+
+1. Adding Diets
+ - Test case 1:
+ * Add a complete diet entry.
+ * Command: `add-diet calories/700 protein/25 carb/55 fat/15 datetime/2023-10-12 07:30`
+ * Expected Outcome: Diet entry is successfully added with 700 calories, 25mg protein, 55mg carb, and 15mg fat.
+ - Test case 2:
+ * Attempt to add a diet entry with a future datetime.
+ * Command: `add-diet calories/800 protein/30 carb/60 fat/20 datetime/3024-01-01 08:00`
+ * Expected Outcome: Error indicating the datetime cannot be in the future.
+
+2. Editing Diets
+ - Test case 1:
+ * Edit a specific diet entry.
+ * Command: `edit-diet 2 calories/900 protein/40 carb/70 fat/25 datetime/2023-10-13 09:00`
+ * Expected Outcome: The 2nd diet entry is updated with the new values.
+ - Test case 2:
+ * Edit a diet entry with only one parameter.
+ * Command: `edit-diet 3 fat/30`
+ * Expected Outcome: Only the fat value of the 3rd diet entry is updated.
+
+3. Deleting Diets
+ - Test case 1:
+ * Delete a specific diet entry.
+ * Command: `delete-diet 2`
+ * Expected Outcome: The 2nd diet entry is successfully deleted.
+ - Test case 2:
+ * Attempt to delete a non-existent diet entry.
+ * Command: `delete-diet 5`
+ * Expected Outcome: Error indicating the diet entry does not exist.
+
+4. Listing Diets
+ - Test case 1:
+ * List all diet entries.
+ * Command: `list-diet`
+ * Expected Outcome: All existing diet entries are displayed.
+
+5. Finding Diets
+ - Test case 1:
+ * Find diets recorded on a specific date.
+ * Command: `find-diet 2023-10-12`
+ * Expected Outcome: Diets recorded on 12th October 2023 are displayed.
+ - Test case 2:
+ * Find diets on a date with no entries.
+ * Command: `find-diet 2023-11-01`
+ * Expected Outcome: No diets are displayed.
+
+#### Diet Goals
+
+1. Setting diet goals
+ * Prerequisite: There are no similar goals present
+ * Test case 1:
+ * There are no diet goals constructed.
+ * `set-diet-goal DAILY calories/500` creates a daily healthy calories goal with a target value of 500
+ * Test case 2:
+ * There are no diet goals constructed.
+ * `set-diet-goal WEEKLY calories/500 fat/600` Creates 2 weekly healthy nutrient goals: calories and fat.
+ * Test case 3:
+ * There is a daily healthy calories goal present.
+ * `set-diet-goal DAILY calories/500` will result in an error since the goal is already present.
+ * Test case 4:
+ * There is a daily healthy calories goal present.
+ * `set-diet-goal DAILY unhealthy calories/500` will result in an error as a nutrient goal cannot be healthy
+ and unhealthy at the same time.
+ * Test case 5:
+ * There is a daily healthy calories goal present with a target value of 1000
+ * `set-diet-goal WEEKLY healthy calories/500` will result in an error since the value of the daily diet goal
+ is greater than the value of weekly diet goal.
+2. Listing diet goals
+ * Test case 1:
+ * `list-diet-goal` lists all the diet goals that are created and present in the diet goal records.
+3. Deleting diet goals
+ * Test case 1:
+ * There is one diet goal present in the diet goal records.
+ * `delete-diet-goal 1` removes the goal from the diet goal records.
+ * Test case 2:
+ * `delete-diet-goal` without any index to delete the goal or non-positive integers provided
+ or the value is greater than the number of diet goals present in the diet goal records, error will be thrown.
+4. Editing diet goals
+ * This is similar to setting diet goal, but the goal is required to be in the diet goals record first.
+ * Users are only allowed to edit the target value of the goal. There is no edit supported to edit diet goal
+ types or diet goal time span.
+ * Test case 1:
+ * No goals present in the records.
+ * `edit-diet-goal WEEKLY calories/5000` will return an error since there are no associated goals to
+ make an edit to the goal's target value.
+ * Test case 2:
+ * Weekly healthy calories goal is present with a target value of 20.
+ * `edit-diet-goal WEEKLY calories/5000` will update the target value of weekly healthy calories goal to 5000.
+ * Similar to setting diet goals, the weekly goal values should always be greater than the daily goal values.
+
+
+### Sleep Management
+
+#### Sleep Records
+1. Adding Sleep
+ - Test case 1:
+ * Add a sleep record.
+ * Command: `add-sleep start/2021-09-01 06:00 end/2021-09-01 07:00`
+ * Expected Outcome: Sleep record is successfully added with start time of 2021-09-01 06:00 and end time of
+ 2021-09-01 07:00.
+ - Test case 2:
+ * Attempt to add a sleep record with a future start time.
+ * Command: `add-sleep start/3024-01-01 08:00 end/3024-01-01 09:00`
+ * Expected Outcome: Error indicating the start time cannot be in the future.
+ - Test case 3:
+ * Attempt to add a sleep record with a start time later than the end time.
+ * Command: `add-sleep start/2021-09-01 08:00 end/2021-09-01 07:00`
+ * Expected Outcome: Error indicating the start time cannot be later than the end time.
+
+2. Editing Sleep
+ - Test case 1:
+ * Edit a specific sleep record.
+ * Command: `edit-sleep 2 start/2021-09-01 09:00 end/2021-09-01 10:00`
+ * Expected Outcome: The 2nd sleep record is updated with the new values.
+ - Test case 2:
+ * Edit a sleep record with only one parameter.
+ * Command: `edit-sleep 3 end/2021-09-01 11:00`
+ * Expected Outcome: Error indicating the start time is not specified.
+ - Test case 3:
+ * Edit a sleep record with a invalid index.
+ * Command: `edit-sleep -1011 start/2021-09-01 09:00 end/2021-09-01 10:00`
+ * Expected Outcome: Error indicating the index is invalid.
+
+3. Deleting Sleep
+
+ **Assuming there are 4 sleep records in the sleep list**
+ - Test case 1:
+ * Delete a specific sleep record.
+ * Command: `delete-sleep 2`
+ * Expected Outcome: The 2nd sleep record is successfully deleted.
+ - Test case 2:
+ * Attempt to delete a non-existent sleep record.
+ * Command: `delete-sleep 5`
+ * Expected Outcome: Error indicating the sleep record does not exist.
+4. Listing Sleep
+ - Test case 1:
+ * List all sleep records.
+ * Command: `list-sleep`
+ * Expected Outcome: All existing sleep records are displayed.
+
+
+#### Sleep Goals
+1. Setting sleep goals
+
+ - Test case 1:
+ * Set a daily sleep duration goal.
+ * Command: `set-sleep-goal type/duration period/daily target/90`
+ * Expected Outcome: Daily sleep duration goal of 90 minutes is set successfully.
+ - Test case 2:
+ * Set a weekly sleep duration goal.
+ * Command: `set-sleep-goal type/duration period/weekly target/600`
+ * Expected Outcome: Weekly sleep duration goal of 600 minutes is set successfully.
+ - Test case 3:
+ * Attempt to set a duplicate daily sleep duration goal.
+
+ **Assuming there is a daily sleep duration goal**
+
+ * Command: `set-sleep-goal type/duration period/daily target/90`
+ * Expected Outcome: Error indicating the daily sleep duration goal already exists.
+
+2. Editing sleep goals
+ - Test case 1:
+ * Edit an existing daily sleep duration goal.
+ * Command: `edit-sleep-goal type/duration period/daily target/120`
+ * Expected Outcome: Daily sleep duration goal is updated to 120 minutes.
+ - Test case 2:
+ * Edit a non-existent weekly sleep duration goal.
+ * Command: `edit-sleep-goal type/duration period/weekly target/1000`
+ * Expected Outcome: Error indicating no existing weekly sleep duration goal.
+
+3. Listing sleep goals
+ - Test case 1:
+ * List all set sleep goals.
+ * Command: `list-sleep-goal`
+ * Expected Outcome: All set sleep goals along with their details are listed.
+
+### Miscellaneous
+
+1. Finding Records
+ * Test case:
+ * Command: `find-diet 2023-12-31`
+ * Expected Outcome: All records on 31st December 2023 are displayed.
+
+1. Saving Files
+ * Test case:
+ * Command: `save`
+ * Expected Outcome: Data are safely saved into the files.
+
+1. Exiting AthletiCLI:
+ * Test case 1:
+ * Immediately after detecting a format error in the saved files.
+ * Command: `bye`
+ * Expected Outcome: AthletiCLI is exited without rewriting the files.
+ * Test case 2:
+ * During normal execution.
+ * Command: `bye`
+ * Expected Outcome: AthletiCLI is exited and the files are safely saved.
+
+1. Viewing Help Messages:
+ * Test case 1:
+ * Command: `help`
+ * Expected Outcome: A list containing the syntax of all commands is shown.
+ * Test case 2:
+ * Command: `help add-diet`
+ * Expected Outcome: The syntax of the `add-diet` command is shown.
diff --git a/docs/Gemfile b/docs/Gemfile
new file mode 100644
index 0000000000..4aef0833b3
--- /dev/null
+++ b/docs/Gemfile
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
+
+gem 'jekyll'
+gem 'github-pages', group: :jekyll_plugins
+gem 'wdm', '~> 0.1.0' if Gem.win_platform?
+gem 'webrick'
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..cbca12285d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,19 @@
-# Duke
+---
+permalink: /
+layout: page
+title: About AthletiCLI
+feature_text: |
+ # AthletiCLI
+ Your all-in-one solution to track, analyse, and optimize your athletic performance.
+feature_image: "https://picsum.photos/1300/400?image=989"
+---
-{Give product intro here}
+[![](https://github.com/AY2324S1-CS2113-T17-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2324S1-CS2113-T17-1/tp/actions)
-Useful links:
-* [User Guide](UserGuide.md)
-* [Developer Guide](DeveloperGuide.md)
-* [About Us](AboutUs.md)
+**AthletiCLI** is your all-in-one solution to track, analyse, and optimize your athletic performance. Designed for the
+committed athlete, this command-line interface (CLI) tool not only keeps tabs on your physical activities but also
+covers dietary habits, sleep metrics, and more.
+
+* If you are interested in using AthletiCLI, head over to the [User Guide](UserGuide.html).
+* If you are interested about developing AthletiCLI, the [Developer Guide](DeveloperGuide.html) is a good place to start.
+* If you would like to learn more about our development team, please visit the [About Us](AboutUs.html) page.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..47dc904f75 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,916 @@
-# User Guide
+---
+layout: page
+title: User Guide
+---
+*Your all-in-one solution to track, analyse, and optimize your athletic performance.*
+*Designed for the committed athlete, this command-line interface (CLI) tool not only keeps track of your physical
+activities but also covers dietary habits, sleep metrics, and more.*
-## Introduction
+* Table of Contents
+{:toc}
-{Give a product intro}
+## 🚀 Quick Start
-## Quick Start
+* ✅ Ensure you have the required runtime environment installed on your computer.
+* ✅ Download the latest AthletiCLI from the official repository.
+* ✅ Copy the downloaded file to a folder you want to designate as the home for AthletiCLI.
+* ✅ Open a command terminal, cd into the folder where you copied the file, and run `java -jar AthletiCLI.jar` .
-{Give steps to get started quickly}
+## Features
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+**Notes about Command Format**
-## Features
+* Words in UPPER_CASE are parameters provided by the user.
+* Parameters need to be specified in the given order unless specified otherwise.
+* Parameters enclosed in square brackets [] are optional.
-{Give detailed description of each feature}
+**Notes about lack of Goal Delete for Sleep**
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+The absence of a "Goal Delete" feature for Sleep in the current version of AthletiCLI, while present for Diet and Activity, can be concisely justified as follows:
-Format: `todo n/TODO_NAME d/DEADLINE`
+1. **Diversity of Diet and Acitivity Goals:** The Diet and Activity features encompasses a wider range of goals compared to Sleep. With such variability, users might frequently need to delete diet goals, making a delete function more essential.
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+2. **Stability of Sleep Goals:** There are only 4 settable goals for sleep. This stability reduces the immediate need for a delete feature, as users are less likely to remove these goals frequently.
-Example of usage:
+3. **Planned for Future Implementation:** The absence of this feature in the current version for Sleep does not indicate it will never be implemented. It is planned for a future update, aligning with a phased development approach.
-`todo n/Write the rest of the User Guide d/next week`
+## 🏃 Activity Management
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+- [Adding Activities](#-adding-activities)
+- [Deleting Activities](#-deleting-activities)
+- [Listing Activities](#-listing-activities)
+- [Editing Activities](#-editing-activities)
+- [Setting Activity Goals](#-setting-activity-goals)
+- [Editing Activity Goals](#-editing-activity-goals)
+- [Listing Activity Goals](#-listing-activity-goals)
+- [Deleting Activity Goals](#-deleting-activity-goals)
+
+### ➕ Adding Activities:
+
+`add-activity` `add-run` `add-swim` `add-cycle`
+
+You can record your activities in AtheltiCLI by adding different activities including running, cycling, and swimming.
+A brief summary of the activity will be shown after adding the activity. Use the detailed list command to access the
+full activity insights.
+
+**Syntax:**
+
+* `add-activity CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME`
+* `add-run CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME elevation/ELEVATION`
+* `add-swim CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME style/STYLE`
+* `add-cycle CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME elevation/ELEVATION`
+
+**Parameters:**
+
+* CAPTION: A short description of the activity.
+* DURATION: The duration of the activity in ISO Time Format: HH:mm:ss.
+* DISTANCE: The distance of the activity in meters. It must be a non-negative number smaller than 1000001.
+* DATETIME: The date and time of the start of the activity. It must follow the ISO Date Time Format yyyy-MM-dd HH:mm,
+ must be valid, and cannot be in the future.
+* ELEVATION: The elevation gain of a run or cycle in meters. It must be a number with an absolute value smaller than
+10001.
+* STYLE: The style of the swim. It must be one of the following: freestyle, backstroke, breaststroke, butterfly.
+
+**Examples:**
+
+* `add-activity Morning Run duration/01:00:00 distance/10000 datetime/2021-09-01 06:00`
+* `add-cycle Evening Ride duration/02:00:00 distance/20000 datetime/2021-09-01 18:00 elevation/1000`
+* `add-swim Evening Swim duration/01:00:00 distance/1000 datetime/2023-10-16 20:00 style/freestyle`
+
+---
+
+### ➖ Deleting Activities:
+
+`delete-activity`
+
+Accidentally added an activity? You can quickly delete any type of activity including run, swims and cycles by using
+the following command.
+
+**Syntax:**
+
+* `delete-activity INDEX`
+
+**Parameters:**
+
+* INDEX: The index of the activity as shown in the displayed activity list. Note, that the list is sorted by
+ date and that the index must be a positive number which is not larger than the number of activities recorded.
+
+**Examples:**
+
+* `delete-activity 2` Deletes the second activity in the activity list.
+* `delete-activity 1` Deletes the most recent activity in the activity list.
+
+---
+
+### 📅 Listing Activities:
+
+`list-activity`
+
+By using this command, you can see all your tracked activities in a list sorted by date. For more
+detailed information about your activities including evaluations like pace (running), speed (cycling) or lap time
+(swimming), you can use the `-d` flag.
+
+**Syntax:**
+
+* `list-activity [-d]`
+
+**Flags:**
+
+* `-d`: Shows a detailed list of the activities.
+
+**Metrics:**
+* Pace: the average time taken to run 1km. Common performance metric for runners.
+* Speed: the average speed of the cycle in km/h. Common performance metric for cyclists.
+* Lap Time: the time taken to swim 1 lap (50m). Common performance metric for swimmers.
+
+**Examples:**
+
+* `list-activity` Shows a brief overview of all activities.
+
+
+
+
+* `list-activity -d` Shows a detailed summary of all activities.
+
+
+
+
+---
+
+### ⚙️ Editing Activities:
+
+`edit-activity` `edit-run` `edit-swim` `edit-cycle`
+
+You can edit your activities in AthletiCLI by editing the activity at the specified index.
+Specify the parameters you want to edit with the corresponding flags. At least one parameter must be specified.
+
+**Syntax:**
+
+* `edit-activity INDEX [caption/CAPTION] [duration/DURATION] [distance/DISTANCE] [datetime/DATETIME]`
+* `edit-run INDEX [caption/CAPTION] [duration/DURATION] [distance/DISTANCE] [datetime/DATETIME] [elevation/ELEVATION]`
+* `edit-swim INDEX [caption/CAPTION] [duration/DURATION] [distance/DISTANCE] [datetime/DATETIME] [style/STYLE]`
+* `edit-cycle INDEX [caption/CAPTION] [duration/DURATION] [distance/DISTANCE] [datetime/DATETIME] [elevation/ELEVATION]`
+
+**Parameters:**
+
+* INDEX: The index of the activity to be edited as shown in the displayed activity list - must be a positive number
+ which is not larger than the number of activities recorded. Note, that the indices are allocated based on the date of the activity.
+* See [adding activities](#-adding-activities) for the other parameters.
+
+**Examples:**
+
+* `edit-activity 1 caption/Morning Run distance/10000`
+* `edit-cycle 2 datetime/2021-09-01 18:00 elevation/1000`
+
+---
+
+### 🔍 Finding Activities:
+
+`find-activity`
+
+You can find all your activities on a specific date in AtheltiCLI.
+
+**Syntax:**
+
+* `find-activity DATE`
+
+**Parameters:**
+
+* DATE: The date of the activity. It must follow the ISO Date Format: yyyy-MM-dd, must be valid and cannot be in
+ the future.
+
+**Example:**
+
+* `find-activity 2021-09-01`
+
+---
+
+### 🎯 Setting Activity Goals:
+
+`set-activity-goal`
+
+You can set goals for specific sports by defining target distance or duration over various periods. The goals can track
+your daily, weekly, monthly, or yearly progress.
+
+**Syntax**
+
+* `set-activity-goal sport/SPORT type/TYPE period/PERIOD target/TARGET`
+
+**Parameters**
+
+* SPORT: The sport for which to set a goal. Options: running, cycling, swimming, general.
+* TYPE: The metric for the goal. Options: distance, duration.
+* PERIOD: The period for the goal. Options: daily, weekly, monthly, yearly. Only activities that are recorded within
+ the period will be counted towards the goal.
+* TARGET: The target value. It must be a non-negative number smaller than 2^31-1. For distance, in meters. For
+ duration, in minutes.
+
+**Examples**
+
+* `set-activity-goal sport/running type/distance period/weekly target/10000` Sets a goal of running 10km per week.
+* `set-activity-goal sport/swimming type/duration period/monthly target/120` Sets a goal of swimming for 2 hours
+ per month.
+
+---
+
+### ⚙️ Editing Activity Goals:
+
+`edit-activity-goal`
+
+You can edit your set goals by specifying the sport, target, and period.
+
+**Syntax**
+
+* `edit-activity-goal sport/SPORT type/TYPE period/PERIOD target/TARGET`
+
+**Parameters**
+
+* TARGET: The new target value. For distance (in meters), for duration (in minutes).
+* See [setting activity goals](#-setting-activity-goals) for the other parameters.
+
+**Examples**
+
+* `edit-activity-goal sport/running type/distance period/weekly target/20000` Adjusts the goal of running distance
+ to 20km per week.
+* `edit-activity-goal sport/swimming type/duration period/monthly target/60` Adjusts the goal of swimming duration
+ to 1 hour per month.
+
+---
+
+### 📅 Listing Activity Goals:
+
+`list-activity-goal`
+
+You can list all your set goals and view your progress towards them.
+
+**Syntax**
+
+* `list-activity-goal`
+
+**Examples**
+
+* `list-activity-goal` Lists all activity goals.
+
+
+
+
+---
+
+### ➖ Deleting Activity Goals:
+
+`delete-activity-goal`
+
+You can delete your set goals by specifying the sport, target, and period.
+
+**Syntax**
+
+* `delete-activity-goal sport/SPORT type/TYPE period/PERIOD`
+
+**Parameters**
+
+* See [setting activity goals](#-setting-activity-goals) for the parameters.
+
+**Examples**
+
+* `delete-activity-goal sport/running type/distance period/weekly` Deletes the weekly running distance goal.
+* `delete-activity-goal sport/swimming type/duration period/monthly` Deletes the monthly swimming duration goal.
+
+---
+
+## 🍏 Diet Management
+
+- [Adding Diets](#-adding-diets)
+- [Editing Diets](#-editing-diets)
+- [Deleting Diets](#-deleting-diets)
+- [Listing Diets](#-listing-diets)
+- [Finding Diets](#-finding-diets)
+- [Adding Diet Goals](#-adding-diet-goals)
+- [Deleting Diet Goals](#-deleting-diet-goals)
+- [Listing Diet Goals](#-listing-diet-goals)
+- [Editing Diet Goals](#-editing-diet-goals)
+
+### ➕ Adding Diets:
+
+`add-diet`
+
+You can record your diet by specifying calories, protein, carbohydrate, and fat intake.
+
+**Syntax:**
+
+* `add-diet calories/CALORIES protein/PROTEIN carb/CARB fat/FAT datetime/DATETIME`
+
+**Parameters:**
+
+* CALORIES: Total calories (in cal) of the meal.
+* PROTEIN: Total protein (in milligrams) of the meal.
+* CARB: Total carbohydrates (in milligrams) of the meal.
+* FAT: Total fat (in milligrams) of the meal.
+* DATETIME: Date and time of the meal in ISO Date Time Format (yyyy-MM-dd HH:mm). It must be valid and cannot be in the
+ future.
+
+**Examples:**
+
+* `add-diet calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` Adds a diet entry with 500 calories,
+ 20mg of protein, 50mg of carbohydrates, and 10mg of fat on 1st September 2021 at 6am.
+* `add-diet calories/2000 datetime/2023-09-01 16:00 fat/10 carb/100 protein/200` Adds a diet entry with 2000 calories,
+ 200mg of protein, 100mg of carbohydrates, and 10mg of fat on 1st September 2023 at 4pm.
+
+---
+
+### ⚙️ Editing Diets:
+
+`edit-diet`
+
+You can modify existing diet entries by specifying the index of the diet you wish to edit.
+
+**Syntax:**
+
+* `edit-diet INDEX [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT] [datetime/DATETIME]`
+
+**Parameters:**
+
+* INDEX: Index of the diet entry (positive integer).
+* See [adding diets](#-adding-diets) for the other parameters.
+
+**Examples:**
+
+* `edit-diet 1 calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` Edits the first diet entry.
+* `edit-diet 1 protein/215` Edits the first diet entry to have 215mg of protein.
+
+*Note: Find the index of your diet entry in the listing section.*
+
+---
+
+### ➖ Deleting Diets:
+
+`delete-diet`
+
+You can remove a diet entry from your records.
+
+**Syntax:**
+
+* `delete-diet INDEX`
+
+**Parameters:**
+
+* INDEX: Index of the diet to be deleted (positive integer).
+
+**Examples:**
+
+* `delete-diet 1` Deletes the first diet entry.
+
+---
+
+### 📅 Listing Diets:
+
+`list-diet`
+
+You can view a list of all your recorded diets.
+
+**Syntax:**
+
+* `list-diet`
+
+**Examples:**
+
+* `list-diet` Lists all diets.
+
+
+
+
+---
+
+### 🔍 Finding Diets:
+
+`find-diet DATE`
+
+You can locate diets recorded on a specific date.
+
+**Syntax:**
+
+* `find-diet DATE`
+
+**Parameters:**
+
+* DATE: Date of the diet in ISO Date Format (yyyy-MM-dd). It must be valid and cannot be in the future.
+
+**Examples:**
+
+* `find-diet 2021-09-01` Finds diets recorded on 1st September 2021.
+
+---
+
+### 🎯 Adding Diet Goals:
+
+`set-diet-goal`
+
+You can create a new daily or weekly diet goal to track your nutrients intake with AtheltiCLI by adding the nutrients you wish to track and the target value for your nutrient goals.
+
+You can set multiple nutrients goals at once with the `set-diet-goal` command.
+
+Do note that you can only set up to the value 999999 and the maximum accumulated value from diets is 1000000.
+
+
+**Syntax:**
+
+* `set-diet-goal [unhealthy] [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT]`
+
+**Parameters:**
+
+* DAILY/WEEKLY: Determines if the goal is set for a day or set for the week. It accepts 2 values.
+ DAILY goals account for what you eat for the day.
+ WEEKLY goals account for what you eat for the week.
+* unhealthy: This determines if you are trying to get more of this nutrient or less of it.
+ If this flag is placed, it means that you are trying to reduce the intake. Hence, exceeding the target value means
+ that you have not achieved your goal. If this flag is absent, it means that you are trying to increase the intake.
+ It is considered achieved if you exceed the target value indicated.
+* CALORIES: Your target value for calories intake, in terms of calories. The target value must be a positive integer up to the value 999999.
+* PROTEIN: Your target for protein intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+* CARB: Your target value for carbohydrate intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+* FAT: Your target value for fat intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+
+You can create one or multiple nutrient goals at once with this command.
+
+**Note: At least one of the nutrients (CALORIES,PROTEIN,CARB,FAT) must be present!**
+
+**Note: A diet goal of the same nutrient cannot be healthy and unhealthy at the same time!**
+
+**Note: No repetitions are allowed for the diet goal of the same nutrient and the same time span.**
+
+**Note: The target value for a weekly goal must be greater than the target value of a daily goal of the same nutrient!**
+
+
+**Examples:**
+
+* `set-diet-goal WEEKLY calories/500 fat/600` Creates 2 weekly nutrient goals if they have not been created:
+calories with a target value of 500 calories and fat of 600 mg.
+
+* `set-diet-goal DAILY calories/500` Creates a daily calories goal of target value of 500 calories if goal is not created.
+
+** `set-diet-goal DAILY unhealthy calories/500` Creates an unhealthy daily calories goal of target value of
+500 calories if goal is not created.
+
+**Example of Usage:**
+
+```
+ > set-diet-goal WEEKLY calories/500 fat/600
+ _____________________________________________________________
+ These are your goal(s):
+
+ 1. [HEALTHY] WEEKLY calories intake progress: (0/500)
+
+ 2. [HEALTHY] WEEKLY fat intake progress: (0/600)
+
+ Now you have 2 diet goal(s).
+ _____________________________________________________________
+```
+
+---
+
+### ➖ Deleting Diet Goals:
+
+`delete-diet-goal`
+
+You can delete your diet goals in AtheltiCLI by deleting the goal at the specified index.
+This index will be referenced via `list-diet-goal` command.
+
+**Syntax:**
+
+* `delete-diet-goal INDEX`
+
+**Parameters:**
+
+* INDEX: The index of the diet goal to be deleted. It must be a positive integer and
+it is bounded by the number of diet goals available.
+
+**Examples:**
+
+* `delete-diet-goal 1` Deletes a diet goal that is located on the first index of the list if it exists.
+
+**Example of Usage:**
+
+```
+____________________________________________________________
+ These are your goal(s):
+
+ 1. [HEALTHY] WEEKLY calories intake progress: (0/500)
+
+ 2. [HEALTHY] WEEKLY fat intake progress: (0/600)
+
+ Now you have 2 diet goal(s).
+____________________________________________________________
+
+> delete-diet-goal 1
+____________________________________________________________
+ The following goal has been deleted:
+
+ [HEALTHY] WEEKLY calories intake progress: (0/500)
+
+____________________________________________________________
+```
+
+---
+
+### 📅 Listing Diet Goals:
+
+`list-diet-goal`
+
+You can list all your diet goals in AtheltiCLI.
+
+**Syntax:**
+
+* `list-diet-goal`
+
+**Examples:**
+
+* `list-diet-goal`
+
+**Example of Usage:**
+
+```
+> list-diet-goal
+____________________________________________________________
+ These are your goal(s):
+
+ 1. [HEALTHY] WEEKLY fat intake progress: (0/600)
+
+ Now you have 1 diet goal(s).
+____________________________________________________________
+```
+
+---
+
+### ⚙️️ Editing Diet Goals:
+
+`edit-diet-goal`
+
+You can edit the target value of your diet goals in AtheltiCLI, redefining the target value for the specified nutrient.
+
+This command takes in at least 2 arguments. You are able to edit multiple diet goals target value of the same time frame at once.
+No repetition is allowed. The diet goal needs to be present before any edits is allowed.
+
+Do note that you can only set up to the value 999999 and the maximum accumulated value from diets is 1000000.
+
+**Syntax:**
+
+* `edit-diet-goal [unhealthy] [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT]`
+
+**Parameters:**
+
+* DAILY/WEEKLY: This determines if the goal you want to edit is a daily goal or a weekly goal. It accepts 2 values.
+ DAILY goals account for what you eat for the day.
+ WEEKLY goals account for what you eat for the week.
+* unhealthy: This determines if you are trying to get more of this nutrient or less of it.
+This flag is used to change target values of goals that are set as unhealthy previously.
+
+* CALORIES: Your target value for calories intake, in terms of cal. The target value must be a positive integer up to the value 999999.
+* PROTEIN: The target for protein intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+* CARB: Your target value for carbohydrate intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+* FAT: Your target value for fat intake, in terms of milligrams. The target value must be a positive integer up to the value 999999.
+
+
+**Note: At least one of the nutrients (CALORIES,PROTEIN,CARB,FAT) must be present!**
+
+**Note: The target value for a weekly goal must be greater than the target value of a daily goal of the same nutrient!**
+
+You can edit one or multiple nutrient goals with this command.
+
+**Examples:**
+
+* `edit-diet-goal DAILY calories/5000 protein/200 carb/500 fat/100`
+Edits multiple nutrients goals if all of them exists and the corresponding new target value is valid.
+* `edit-diet-goal WEEKLY calories/5000`
+Edits a single calories goal target value to 5000 calories if the goal exists and new target value is valid.
+
+**Example of Usage:**
+
+```
+____________________________________________________________
+ These are your goal(s):
+
+ 1. [HEALTHY] WEEKLY fat intake progress: (0/600)
+
+ Now you have 1 diet goal(s).
+____________________________________________________________
+
+> edit-diet-goal WEEKLY fat/50
+____________________________________________________________
+ These are your goal(s):
+
+ 1. [HEALTHY] WEEKLY fat intake progress: (0/50)
+
+ Now you have 1 diet goal(s).
+____________________________________________________________
+```
+
+---
+
+## 🛌 Sleep Management
+
+- [Adding Sleep](#-adding-sleep)
+- [Listing Sleep](#-listing-sleep)
+- [Deleting Sleep](#-deleting-sleep)
+- [Editing Sleep](#-editing-sleep)
+- [Finding Sleep](#-finding-sleep)
+- [Adding Sleep Goals](#-adding-sleep-goals)
+- [Listing Sleep Goals](#-listing-sleep-goals)
+- [Editing Sleep Goals](#-editing-sleep-goals)
+
+### ➕ Adding Sleep:
+
+`add-sleep`
+
+You can record your sleep timings in AtheltiCLI by adding your sleep start and end time. It also automagically calculates for you the duration of your sleep, as well as the sleep date.
+
+**Syntax:**
+
+* `add-sleep start/START end/END`
+
+**Parameters:**
+
+* START: The start time of the sleep. It must follow the ISO Date Time Format: yyyy-MM-dd HH:mm, must be valid
+ and cannot be in the future.
+
+* END: The end time of the sleep. It must follow the ISO Date Time Format: yyyy-MM-dd HH:mm, must be valid and
+ cannot be in the future.
+
+**Examples:**
+
+Take note that all sleep entries have an associated date.
+
+All sleep entries with a start time before 06:00 will be taken to represent the previous days sleep.
+
+* `add-sleep start/2023-01-20 02:00 end/2023-01-20 08:00` will be taken to represent the sleep record on `2022-01-19`, which is the day before, since the start time is before 06:00 on `2022-01-20`.
+
+* `add-sleep start/2022-01-20 22:00 end/2022-01-21 06:00` will be taken to represent the sleep record on `2022-01-20`, since the start time is after 06:00 on `2022-01-20`.
+
+---
+
+### 📅 Listing Sleep:
+
+`list-sleep`
+
+You can see all your tracked sleep records in a list by using this command.
+
+**Syntax:** `list-sleep`
+
+**Example:** `list-sleep`
+
+---
+
+### ➖ Deleting Sleep:
+
+`delete-sleep`
+
+Accidentally added a sleep record? You can quickly delete sleep records by using the following command.
+The index must be a positive number and is not larger than the number of sleep records recorded.
+
+**Syntax:**
+
+* `delete-sleep INDEX`
+
+**Parameters:**
+
+* INDEX: The index of the sleep record you wish to delete. It must be a positive number and is not larger than the number of sleep records recorded.
+Refer to the list-sleep command for the index of the sleep record you wish to delete.
+
+**Examples:**
+
+Assuming that there are 5 sleep records in the list:
+
+* `delete-sleep 5` will delete the 5th sleep record in the sleep records list.
+* `delete-sleep 1` will delete the 1st sleep record in the sleep records list.
+
+---
+
+### ⚙️️ Editing Sleep:
+
+`edit-sleep`
+
+You can modify existing sleep records in AtheltiCLI by specifying the sleep's index and then providing the new start and end times.
+
+**Syntax:**
+
+* `edit-sleep INDEX start/START end/END`
+
+**Parameters:**
+
+* INDEX: The index of the sleep record you wish to edit. It must be a positive number and is not larger than the number of sleep records recorded.
+* START: The new start time of the sleep. It must follow the ISO Date Time Format: yyyy-MM-dd HH:mm, must be
+ valid and cannot be in the future.
+* END: The new end time of the sleep. It must follow the ISO Date Time Format: yyyy-MM-dd HH:mm, must be valid and
+ cannot be in the future.
+
+**Examples:**
+
+Assuming that there are 5 sleep records in the list:
+
+* `edit-sleep 5 start/2023-01-20 02:00 end/2023-01-20 08:00` will edit the 5th sleep record in the sleep records list to have a start time of `2023-01-20 02:00` and an end time of `2023-01-20 08:00`.
+
+* `edit-sleep 1 start/2022-01-20 22:00 end/2022-01-21 06:00` will edit the 1st sleep record in the sleep records list to have a start time of `2022-01-20 22:00` and an end time of `2022-01-21 06:00`.
+
+---
+
+### 🔍 Finding Sleep:
+
+`find-sleep DATE`
+
+You can find your sleep record on a specific date in AtheltiCLI.
+
+**Syntax:**
+
+* `find-sleep DATE`
+
+**Parameters:**
+
+* DATE: The date of the sleep. It must follow the ISO Date Format: yyyy-MM-dd, must be valid and cannot be in the
+ future.
+
+**Examples:**
+
+* `find-sleep 2021-09-01`
+
+---
+
+### 🎯 Setting Sleep Goals:
+
+`set-sleep-goal`
+
+You can set goals for your sleep AthletiCLI by setting the target duration specified in minutes. Tracking can be done for the past day, week, month or year.
+
+**NOTE: Only one sleep goal can be set for each time period.**
+
+**Syntax:**
+* `set-sleep-goal type/TYPE period/PERIOD target/TARGET`
+
+**Parameters:**
+* TYPE: The type of sleep goal. It must be the following: `duration`.
+* PERIOD: The period for which you want to set a goal. It must be one of the following: `daily, weekly, monthly, yearly`. Only sleeps that are recorded within the period from the current time will be counted towards the goal.
+* TARGET: The target value. It must be a positive number. For duration, it is in minutes.
+
+**Examples:**
+* `set-sleep-goal type/duration period/daily target/420` Sets a goal of sleeping 7 hours per day.
+* `set-sleep-goal type/duration period/weekly target/2940` Sets a goal of sleeping 49 hours per week.
+
+---
+
+### 📅 Editing Sleep Goals:
+
+`edit-sleep-goal`
+
+You can edit your already set sleep goals by mentioning the type, period, and target of the goal you want to edit.
+
+**Syntax:**
+* `edit-sleep-goal type/TYPE period/PERIOD target/TARGET`
+
+**Parameters:**
+* TYPE: The type of sleep goal. It must be the following: `duration`.
+* PERIOD: The period for which you want to set a goal. It must be one of the following: `daily, weekly, monthly, yearly`. Only sleeps that are recorded within the period from the current timewill be counted towards the goal.
+* TARGET: The target value. It must be a positive number. For duration, it is in minutes.
+
+**Examples:**
+* `edit-sleep-goal type/duration period/daily target/360` Edits the daily goal to sleeping 6 hours per day.
+* `edit-sleep-goal type/duration period/weekly target/2520` Edits the weekly goal to sleeping 42 hours per week.
+
+---
+
+### 📅 Listing Sleep Goals:
+
+`list-sleep-goal`
+
+You can list all your sleep goals in AthletiCLI and see your progress towards them.
+
+---
+
+## Miscellaneous
+
+### 🔍 Finding Records:
+
+You can find all your records, including activities, sleeps, and diets, on a specific date in AtheltiCLI.
+
+**Syntax:**
+
+* `find DATE`
+
+**Parameters:**
+
+* `DATE`: The date of the records. It must follow the ISO Date Format `yyyy-MM-dd`, must be valid and cannot be in
+ the future.
+
+**Example:**
+
+* `find 2023-11-01`
+
+---
+
+### 📦 Saving Files:
+
+You can save files while using AthletiCLI if you want to, rather than waiting until the AthletiCLI exits to automatically save them.
+
+**Syntax:**
+
+* `save`
+
+---
+
+### 👋 Exiting AthletiCLI:
+
+You can use the `bye` command at any time to safely store the file and exit AthletiCLI.
+
+**Syntax:**
+
+* `bye`
+
+---
+
+### ℹ️ Viewing Help Messages:
+
+If you forget a command, you can always use the `help` command to see their syntax.
+
+**Syntax:**
+
+* `help [COMMAND]`
+
+**Parameters:**
+
+* `COMMAND`: The command you want to view. If it is omitted, a list containing the syntax of all commands will be shown.
+
+**Examples:**
+
+* `help` lists the syntax of all commands.
+* `help add-diet` shows the syntax of the `add-diet` command.
+
+---
## FAQ
+ **Q: *Am I allowed to update the storage files?***
+
+ **A**:
+ While it is generally advisable not to edit the contents of the storage file, you do have the option to make updates.
+ Please exercise caution when doing so. Incorrect edits to the storage file can result in data loss. If AthleticCLI
+ encounters incorrect format of the file contents, it will prompt you to exit using the
+ [bye](#exiting-athleticli) command.
+ Continuing with the program in such cases will lead to the deletion of all data in the file.
+
+
+---
+## Summary of Commands
+
+### Activity Management
+
+| **Command** | **Syntax** | **Parameters** | **Examples** |
+|---------------------------|-----------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------------|
+| `add-activity` | `add-activity CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME` | CAPTION, DURATION, DISTANCE, DATETIME | `add-activity Morning Run duration/01:00:00 distance/10000 datetime/2021-09-01 06:00` |
+| `add-run` | `add-run CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME elevation/ELEVATION` | CAPTION, DURATION, DISTANCE, DATETIME, ELEVATION | `add-run NY Marathon duration/03:33:17 distance/42125 datetime/2023-11-05 07:00` |
+| `add-swim` | `add-swim CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME style/STYLE` | CAPTION, DURATION, DISTANCE, DATETIME, STYLE | `add-swim Evening Swim duration/01:00:00 distance/1000 datetime/2023-10-16 20:00 style/freestyle` |
+| `add-cycle` | `add-cycle CAPTION duration/DURATION distance/DISTANCE datetime/DATETIME elevation/ELEVATION` | CAPTION, DURATION, DISTANCE, DATETIME, ELEVATION | `add-cycle Evening Ride duration/02:00:00 distance/20000 datetime/2021-09-01 18:00 elevation/1000` |
+| `delete-activity` | `delete-activity INDEX` | INDEX | `delete-activity 2` |
+| `list-activity` | `list-activity [-d]` | -d | `list-activity`, `list-activity -d` |
+| `edit-activity` | `edit-activity INDEX [caption/CAPTION] [duration/DURATION] [distance/DISTANCE] [datetime/DATETIME]` | INDEX, CAPTION, DURATION, DISTANCE, DATETIME | `edit-activity 1 caption/Morning Run distance/10000` |
+| `edit-run` | Similar to `edit-activity` but with elevation. | Same as `edit-activity` with ELEVATION | - |
+| `edit-swim` | Similar to `edit-activity` but with style. | Same as `edit-activity` with STYLE | - |
+| `edit-cycle` | Similar to `edit-activity` but with elevation. | Same as `edit-activity` with ELEVATION | `edit-cycle 2 datetime/2021-09-01 18:00 elevation/1000` |
+| `find-activity` | `find-activity DATE` | DATE | `find-activity 2021-09-01` |
+| `set-activity-goal` | `set-activity-goal sport/SPORT type/TYPE period/PERIOD target/TARGET` | SPORT, TYPE, PERIOD, TARGET | `set-activity-goal sport/running type/distance period/weekly target/10000` |
+| `edit-activity-goal` | `edit-activity-goal sport/SPORT type/TYPE period/PERIOD target/TARGET` | SPORT, TYPE, PERIOD, TARGET | `edit-activity-goal sport/running type/distance period/weekly target/20000` |
+| `list-activity-goal` | `list-activity-goal` | None | `list-activity-goal` |
+| `delete-activity-goal` | `delete-activity-goal sport/SPORT type/TYPE period/PERIOD` | SPORT, TYPE, PERIOD | `delete-activity-goal sport/running type/distance period/weekly` |
+
+### Diet Management
+
+| **Command** | **Syntax** | **Parameters** | **Examples** |
+|---------------------------|----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|--------------------------------------------------------|
+| `add-diet` | `add-diet calories/CALORIES protein/PROTEIN carb/CARB fat/FAT datetime/DATETIME` | CALORIES, PROTEIN, CARB, FAT, DATETIME | `add-diet calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` |
+| `edit-diet` | `edit-diet INDEX [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT] [datetime/DATETIME]` | INDEX, [CALORIES], [PROTEIN], [CARB], [FAT], [DATETIME] | `edit-diet 1 calories/500 protein/20 carb/50 fat/10 datetime/2021-09-01 06:00` |
+| `delete-diet` | `delete-diet INDEX` | INDEX | `delete-diet 1` |
+| `list-diet` | `list-diet` | None | `list-diet` |
+| `find-diet` | `find-diet DATE` | DATE | `find-diet 2021-09-01` |
+| `set-diet-goal` | `set-diet-goal [unhealthy] [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT]` | DAILY/WEEKLY, [unhealthy], [CALORIES], [PROTEIN], [CARB], [FAT] | `set-diet-goal WEEKLY calories/500 fat/600` |
+| `edit-diet-goal` | `edit-diet-goal [unhealthy] [calories/CALORIES] [protein/PROTEIN] [carb/CARB] [fat/FAT]` | DAILY/WEEKLY, [unhealthy], [CALORIES], [PROTEIN], [CARB], [FAT] | `edit-diet-goal WEEKLY calories/500 fat/600` |
+| `delete-diet-goal` | `delete-diet-goal INDEX` | INDEX | `delete-diet-goal 1` |
+| `list-diet-goal` | `list-diet-goal` | None | `list-diet-goal` |
+
+
+### Sleep Management
-**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+| **Command** | **Syntax** | **Parameters** | **Examples** |
+|---------------------------|-------------------------------------------------------------------------------------|--------------------------------------------------------|----------------------------------------------------------|
+| `add-sleep` | `add-sleep start/START end/END` | START, END | `add-sleep start/2023-01-20 02:00 end/2023-01-20 08:00` |
+| `list-sleep` | `list-sleep` | None | `list-sleep` |
+| `delete-sleep` | `delete-sleep INDEX` | INDEX | `delete-sleep 1` |
+| `edit-sleep` | `edit-sleep INDEX start/START end/END` | INDEX, START, END | `edit-sleep 1 2023-01-20 02:00 2023-01-20 08:00` |
+| `find-sleep` | `find-sleep DATE` | DATE | `find-sleep 2021-09-01` |
+| `set-sleep-goal` | `set-sleep-goal type/TYPE period/PERIOD target/TARGET` | TYPE, PERIOD, TARGET | `set-sleep-goal type/duration period/daily target/420` |
+| `edit-sleep-goal` | `edit-sleep-goal type/TYPE period/PERIOD target/TARGET` | TYPE, PERIOD, TARGET | `edit-sleep-goal type/duration period/daily target/360` |
+| `list-sleep-goal` | `list-sleep-goal` | None | `list-sleep-goal` |
-## Command Summary
-{Give a 'cheat sheet' of commands here}
+### Miscellaneous
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+| **Command** | **Syntax** | **Parameters** | **Examples** |
+|---------------------------|-------------------------------------------------------------------------------------|--------------------------------------------------------|----------------------------------------------------------|
+| `find` | `find DATE` | DATE | `find 2023-11-01` |
+| `save` | `save` | None | `save` |
+| `bye` | `bye` | None | `bye` |
+| `help` | `help [COMMAND]` | [COMMAND] | `help`, `help add-diet` |
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..250fbcd2af
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,41 @@
+remote_theme: skylee03/alembic@4.1.1
+plugins:
+ - jekyll-remote-theme
+ - jekyll-redirect-from
+ - jemoji
+markdown: kramdown
+sass:
+ style: compressed
+encoding: utf-8
+lang: en-US
+title: "AthletiCLI"
+url: "https://ay2324s1-cs2113-t17-1.github.io/tp/"
+repo: "https://github.com/AY2324S1-CS2113-T17-1/tp"
+css_inline: true
+fonts:
+ preconnect_urls:
+ - https://fonts.gstatic.com
+ font_urls:
+ - https://fonts.googleapis.com/css2?family=Alegreya:wght@400;700&display=swap
+navigation_header:
+ - title: Home
+ url: /
+ - title: User Guide
+ url: /UserGuide.html
+ - title: Developer Guide
+ url: /DeveloperGuide.html
+ - title: About Us
+ url: /AboutUs.html
+ - title: GitHub
+ url: https://github.com/AY2324S1-CS2113-T17-1/tp
+navigation_footer:
+ - title: Home
+ url: /
+ - title: User Guide
+ url: /UserGuide.html
+ - title: Developer Guide
+ url: /DeveloperGuide.html
+ - title: About Us
+ url: /AboutUs.html
+ - title: GitHub
+ url: https://github.com/AY2324S1-CS2113-T17-1/tp
\ No newline at end of file
diff --git a/docs/images/ActivityGoalEvaluation.svg b/docs/images/ActivityGoalEvaluation.svg
new file mode 100644
index 0000000000..a30507f6f3
--- /dev/null
+++ b/docs/images/ActivityGoalEvaluation.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/ActivityInheritance.svg b/docs/images/ActivityInheritance.svg
new file mode 100644
index 0000000000..aec653da54
--- /dev/null
+++ b/docs/images/ActivityInheritance.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/ActivityObjectDiagram.svg b/docs/images/ActivityObjectDiagram.svg
new file mode 100644
index 0000000000..ddc5939874
--- /dev/null
+++ b/docs/images/ActivityObjectDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/ActivityParsing.svg b/docs/images/ActivityParsing.svg
new file mode 100644
index 0000000000..a9a6f70fec
--- /dev/null
+++ b/docs/images/ActivityParsing.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/AddActivity.svg b/docs/images/AddActivity.svg
new file mode 100644
index 0000000000..325709b8fe
--- /dev/null
+++ b/docs/images/AddActivity.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/AddActivityGoal.svg b/docs/images/AddActivityGoal.svg
new file mode 100644
index 0000000000..fc07a6ebac
--- /dev/null
+++ b/docs/images/AddActivityGoal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/AthletiCLI-Banner.png b/docs/images/AthletiCLI-Banner.png
new file mode 100644
index 0000000000..4cd2dbab65
Binary files /dev/null and b/docs/images/AthletiCLI-Banner.png differ
diff --git a/docs/images/DataClassDiagram.svg b/docs/images/DataClassDiagram.svg
new file mode 100644
index 0000000000..16b3115b02
--- /dev/null
+++ b/docs/images/DataClassDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/DietGoalClassDiagram.svg b/docs/images/DietGoalClassDiagram.svg
new file mode 100644
index 0000000000..9821ac1812
--- /dev/null
+++ b/docs/images/DietGoalClassDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/DietGoalsSequenceDiagram.svg b/docs/images/DietGoalsSequenceDiagram.svg
new file mode 100644
index 0000000000..e70da653e4
--- /dev/null
+++ b/docs/images/DietGoalsSequenceDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/EditSleepObjectSequenceDiagram.svg b/docs/images/EditSleepObjectSequenceDiagram.svg
new file mode 100644
index 0000000000..d707cfb8ce
--- /dev/null
+++ b/docs/images/EditSleepObjectSequenceDiagram.svg
@@ -0,0 +1,101 @@
+
\ No newline at end of file
diff --git a/docs/images/HelpAddDiet.svg b/docs/images/HelpAddDiet.svg
new file mode 100644
index 0000000000..23b8bed9f1
--- /dev/null
+++ b/docs/images/HelpAddDiet.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/MainClassDiagram.svg b/docs/images/MainClassDiagram.svg
new file mode 100644
index 0000000000..a196983e30
--- /dev/null
+++ b/docs/images/MainClassDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/ParserClassDiagram.png b/docs/images/ParserClassDiagram.png
new file mode 100644
index 0000000000..448e34c34b
Binary files /dev/null and b/docs/images/ParserClassDiagram.png differ
diff --git a/docs/images/Save.svg b/docs/images/Save.svg
new file mode 100644
index 0000000000..18d8c70a53
--- /dev/null
+++ b/docs/images/Save.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/SleepAndSleepListClassDiagram.svg b/docs/images/SleepAndSleepListClassDiagram.svg
new file mode 100644
index 0000000000..47e172ce23
--- /dev/null
+++ b/docs/images/SleepAndSleepListClassDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/architectureDiagram.svg b/docs/images/architectureDiagram.svg
new file mode 100644
index 0000000000..9e4373c141
--- /dev/null
+++ b/docs/images/architectureDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/images/editDietSequenceDiagram.png b/docs/images/editDietSequenceDiagram.png
new file mode 100644
index 0000000000..72a702f909
Binary files /dev/null and b/docs/images/editDietSequenceDiagram.png differ
diff --git a/docs/images/listActivityDetailedShowcase.png b/docs/images/listActivityDetailedShowcase.png
new file mode 100644
index 0000000000..325a501e3d
Binary files /dev/null and b/docs/images/listActivityDetailedShowcase.png differ
diff --git a/docs/images/listActivityGoalShowcase.png b/docs/images/listActivityGoalShowcase.png
new file mode 100644
index 0000000000..59448fec4f
Binary files /dev/null and b/docs/images/listActivityGoalShowcase.png differ
diff --git a/docs/images/listActivityShowcase.png b/docs/images/listActivityShowcase.png
new file mode 100644
index 0000000000..38c266b16a
Binary files /dev/null and b/docs/images/listActivityShowcase.png differ
diff --git a/docs/images/listDietShowcase.png b/docs/images/listDietShowcase.png
new file mode 100644
index 0000000000..60a624c08b
Binary files /dev/null and b/docs/images/listDietShowcase.png differ
diff --git a/docs/images/setDietGoalUmlSequenceDiagram.svg b/docs/images/setDietGoalUmlSequenceDiagram.svg
new file mode 100644
index 0000000000..b191279923
--- /dev/null
+++ b/docs/images/setDietGoalUmlSequenceDiagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/puml/Activity/Activity.puml b/docs/puml/Activity/Activity.puml
new file mode 100644
index 0000000000..c195276e10
--- /dev/null
+++ b/docs/puml/Activity/Activity.puml
@@ -0,0 +1,41 @@
+@startuml
+skinparam classAttributeIconSize 0
+hide circle
+class Activity {
+ -caption
+ -duration
+ -movingTime
+ -distance
+ -startDateTime
+}
+
+class Run {
+-elevationGain
+-averagePace
+}
+
+class Cycle {
+-elevationGain
+-averageSpeed
+}
+
+class Swim {
+-laps
+-style
+-averageLapTime
+}
+
+class ActivityList {
+}
+
+class Data {
+}
+
+Activity <|-- Run
+Activity <|-- Cycle
+Activity <|-- Swim
+ActivityList o-- Activity : consists of * >
+Data o-- ActivityList : 1 >
+
+
+@enduml
diff --git a/docs/puml/Activity/ActivityGoalEvaluation.puml b/docs/puml/Activity/ActivityGoalEvaluation.puml
new file mode 100644
index 0000000000..305b3b0c4d
--- /dev/null
+++ b/docs/puml/Activity/ActivityGoalEvaluation.puml
@@ -0,0 +1,28 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+
+!define LOGIC_COLOR #3333C4
+
+participant ":ActivityGoal" as ActivityGoal LOGIC_COLOR
+participant "data:Data" as Data #lightgrey
+participant "activities:ActivityList" as activities #lightgrey
+
+
+ActivityGoal++
+-> ActivityGoal: isAchieved(data)
+ActivityGoal -> ActivityGoal++: getCurrentValue(data)
+ActivityGoal -> ActivityGoal++: getActivityClass()
+ActivityGoal --> ActivityGoal--: activityClass
+ActivityGoal -> Data++: getActivities()
+Data --> ActivityGoal--: activities
+
+ActivityGoal -> activities++: getTotalDistance/Duration(activityClass, timespan)
+activities -> activities++: filterByTimespan(timespan)
+activities --> activities--: filteredActivities
+activities --> ActivityGoal--: total
+
+ActivityGoal --> ActivityGoal--
+<-- ActivityGoal: isAchieved
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Activity/ActivityObjectDiagram.puml b/docs/puml/Activity/ActivityObjectDiagram.puml
new file mode 100644
index 0000000000..1fa15a867b
--- /dev/null
+++ b/docs/puml/Activity/ActivityObjectDiagram.puml
@@ -0,0 +1,37 @@
+@startuml
+
+object "activities:ActivityList" as activities {
+}
+
+object "run1:Run" as run1 #lightgreen {
+ distance = 5000
+ startDateTime = 2023-11-11
+}
+
+object "run2:Run" as run2 #lightgreen {
+ distance = 5000
+ startDateTime = 2023-11-10
+}
+
+object "swim:Swim" as swim {
+ distance = 1000
+ startDateTime = 2023-10-11
+}
+
+object "cycle:Cycle" as cycle {
+ distance = 40000
+ startDateTime = 2023-10-10
+}
+
+object "activity:Activity" as activity {
+ distance = 100
+ startDateTime = 2023-10-09
+}
+
+activities --> run1
+activities --> run2
+activities --> swim
+activities --> cycle
+activities --> activity
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Activity/ActivityParsing.puml b/docs/puml/Activity/ActivityParsing.puml
new file mode 100644
index 0000000000..fc6ad74004
--- /dev/null
+++ b/docs/puml/Activity/ActivityParsing.puml
@@ -0,0 +1,44 @@
+@startuml
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+participant Parser <> #lightblue
+participant ActivityParser <> #lightgreen
+participant "ac:ActivityChanges" as ActivityChanges #lightgrey
+participant "a:Activity" as Activity #lightgrey
+
+Parser++
+Parser -> ActivityParser++ : parseActivity(arguments)
+
+ActivityParser -> ActivityChanges++ : ActivityChanges()
+ActivityChanges --> ActivityParser-- : ac
+ActivityParser -> ActivityParser++ : parseActivityArguments(ac, arguments, separators)
+
+loop for each separator
+ ActivityParser -> ActivityParser : checkMissingActivityArgument(separatorIndex, separator)
+ ActivityParser -> ActivityParser++ : parseSegment(ac, segment, separator)
+ alt depending on separator
+ ActivityParser -> ActivityChanges++: setCaption(segment)
+ ActivityChanges --> ActivityParser--
+ ActivityParser -> ActivityChanges++ : setDuration(parseDuration(segment))
+ ActivityChanges --> ActivityParser--
+ ... other setters ...
+ ActivityParser -> ActivityChanges++ : setDistance(parseDistance(segment))
+ ActivityChanges --> ActivityParser--
+ end
+ ActivityParser --> ActivityParser -- :
+end
+ActivityParser --> ActivityParser -- :
+
+ActivityParser -> ActivityChanges++ : getCaption()
+ActivityChanges --> ActivityParser-- : caption
+... other getters ...
+ActivityParser -> ActivityChanges++ : getStartDateTime()
+ActivityChanges --> ActivityParser-- : startDateTime
+destroy ActivityChanges
+
+ActivityParser -> Activity++ : Activity(caption, duration, ...)
+Activity --> ActivityParser-- : a
+
+ActivityParser --> Parser-- : a
+
+@enduml
diff --git a/docs/puml/Activity/AddActivity.puml b/docs/puml/Activity/AddActivity.puml
new file mode 100644
index 0000000000..1b01340b8b
--- /dev/null
+++ b/docs/puml/Activity/AddActivity.puml
@@ -0,0 +1,37 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+
+!define LOGIC_COLOR #3333C4
+
+participant ":AthletiCLI" as AthletiCLI #orange
+participant "Parser" as Parser <> #lightblue
+participant "ActivityParser" as ActivityParser <> #lightblue
+participant "a:Activity" as Activity #yellow
+participant "c:AddActivityCommand" as AddActivityCommand #lightgreen
+participant "data:Data" as Data #lightgrey
+participant "activities:ActivityList" as activities #lightgrey
+
+AthletiCLI++
+AthletiCLI -> Parser++: parseCommand(userInput)
+Parser -> ActivityParser++: parseActivity(arguments)
+ActivityParser -> Activity++: Activity()
+Activity --> ActivityParser--: a
+ActivityParser --> Parser--: a
+Parser -> AddActivityCommand++: AddActivityCommand(a)
+AddActivityCommand --> Parser--: c
+Parser --> AthletiCLI--: c
+
+AthletiCLI -> AddActivityCommand++: execute(a, data)
+AddActivityCommand -> Data++: getActivities()
+'Data --> activities++
+'activities --> Data--: activities
+
+Data --> AddActivityCommand--: activities
+AddActivityCommand -> activities++: add(a)
+activities --> AddActivityCommand--
+AddActivityCommand --> AthletiCLI--: message
+
+destroy AddActivityCommand
+@enduml
diff --git a/docs/puml/Activity/AddActivityGoal.puml b/docs/puml/Activity/AddActivityGoal.puml
new file mode 100644
index 0000000000..386f2705f2
--- /dev/null
+++ b/docs/puml/Activity/AddActivityGoal.puml
@@ -0,0 +1,35 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+
+!define LOGIC_COLOR #3333C4
+
+participant ":AthletiCLI" as AthletiCLI #orange
+participant "Parser" as Parser <> #lightblue
+participant "ActivityParser" as ActivityParser <> #lightblue
+participant "goal:ActivityGoal" as ActivityGoal #yellow
+participant "c:SetActivityGoalCommand" as SetActivityGoalCommand #lightgreen
+participant "data:Data" as Data #lightgrey
+participant "goals:ActivityGoalList" as activityGoals #lightgrey
+
+AthletiCLI++
+AthletiCLI -> Parser++: parseCommand(userInput)
+Parser -> ActivityParser++: parseActivityGoal(arguments)
+ActivityParser -> ActivityGoal++: ActivityGoal()
+ActivityGoal --> ActivityParser--: goal
+ActivityParser --> Parser--: goal
+Parser -> SetActivityGoalCommand++: SetActivityGoalCommand(goal)
+SetActivityGoalCommand --> Parser--: c
+Parser --> AthletiCLI--: c
+
+AthletiCLI -> SetActivityGoalCommand++: execute(goal, data)
+SetActivityGoalCommand -> Data++: getActivityGoals()
+
+Data --> SetActivityGoalCommand--: goals
+SetActivityGoalCommand -> activityGoals++: add(goal)
+activityGoals --> SetActivityGoalCommand--
+SetActivityGoalCommand --> AthletiCLI--: message
+
+destroy SetActivityGoalCommand
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Diet/DietGoalClassDiagram.puml b/docs/puml/Diet/DietGoalClassDiagram.puml
new file mode 100644
index 0000000000..b35ced67ab
--- /dev/null
+++ b/docs/puml/Diet/DietGoalClassDiagram.puml
@@ -0,0 +1,81 @@
+@startuml
+'https://plantuml.com/class-diagram
+skinparam classAttributeIconSize 0
+hide circle
+
+abstract class Goal{
+ - timeSpan:TimeSpan
+ + Goal(timeSpan: TimeSpan): Goal
+ + getTimeSpan():TimeSpan
+ + checkData(date: LocalDate, timeSpan: TimeSpan): boolean
+ + {abstract} isAcheived(data:Data): boolean
+
+}
+
+abstract class DietGoal{
+ # nutrient: String
+ # targetValue: int
+ # type: String
+ # achievedSymbol: String
+ # unachievedSymbol: String
+ - dietGoalStringRepresentation: String
+ + DietGoal(timeSpan: TimeSpan, nutrient: String, targetValue:int): DietGoal
+ + getNutrient(): String
+ + getTargetValue(): int
+ + getCurrentValue(data:Data): int
+ + getType(): String
+ + setTargetValue(targetValue: int): void
+ + isSameType(dietGoal: DietGoal): boolean
+ + isSameNutrient(dietGoal: DietGoal): boolean
+ + isSameTimeSpan(dietGoal: DietGoal): boolean
+ + toString(data: Data): String
+ # getSymbol(data: Data): String
+}
+
+class HealthyDietGoal{
+ + TYPE: String
+ # healthyDietGoalSymbol: String
+ # healthyDietGoalStringRepresentation: String
+ - isHealthy: boolean
+ + HealthyDietGoal(timeSpan: TimeSpan, nutrient: String, targetValue: int): HealthyDietGoal
+ + getType(): String
+ + toString(data: Data): String
+}
+
+class UnhealthyDietGoal{
+ + TYPE: String
+ # achievedSymbol
+ # unachievedSymbol
+ # unhealthyDietGoalSymbol: String
+ # unhealthyDietGoalStringRepresentation: String
+ - isHealthy: boolean
+ + UnhealthyDietGoal(timeSpan: TimeSpan, nutrient: String, targetValue: int): HealthyDietGoal
+ + isAcheived(data: Data): boolean
+ + getType(): String
+ + toString(data: Data): String
+ # getSymbol(): String
+
+}
+
+class DietGoalList{
+ - unparseMessage: String
+ + DietGoalList(): DietGoalList
+ + toString(data: Data): String
+ + isDietgoalUnique(dietGoal: DietGoal): boolean
+ + isDietGoalTypeValid(dietGoal: DietGoal): boolean
+ + isTargetValueConsistentWithTimeSpan(newDietGoal: DietGoal): boolean
+ + parse(s: String): DietGoal
+ - validateParseDietGoal(dietGoal: DietGoal): void
+ - createParseNewDietGoal(goalType: String, timeSpan: String, nutrient: String, targetValue: int): DietGoal
+
+
+}
+
+
+Goal <|-- DietGoal
+DietGoal <|-- HealthyDietGoal
+DietGoal <|-- UnhealthyDietGoal
+DietGoalList "1" o-l- "*" DietGoal :contains >
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Diet/DietGoalsSequenceDiagram.puml b/docs/puml/Diet/DietGoalsSequenceDiagram.puml
new file mode 100644
index 0000000000..93b9cc10fe
--- /dev/null
+++ b/docs/puml/Diet/DietGoalsSequenceDiagram.puml
@@ -0,0 +1,57 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+participant ":AthletiCLI" as AthletiCLI #lightblue
+participant ":Parser" as Parser #lightgreen
+participant ":HealthyDietGoal" as healthyDietGoal #lightyellow
+participant ":UnhealthyDietGoal" as unhealthyDietGoal #lightyellow
+participant ":SetDietGoalCommand" as SetDietGoalCommand #lightpink
+participant "temp:DietGoalList" as tempDietGoalList #yellow
+participant "data:Data" as dataData
+participant "data:DietGoalList" as dataDietGoalList #yellow
+
+
+'autonumber
+AthletiCLI++
+AthletiCLI -> Parser++ : ParseCommand("set-diet-goal WEEKLY fat/1")
+Parser -> Parser++ : ParseDietGoalSetEdit("WEEKLY fat/1")
+create tempDietGoalList
+Parser -> tempDietGoalList++ : dietGoalList()
+tempDietGoalList --> Parser-- : temp:DietGoalList
+
+ loop number of valid new diet goals
+ alt is healthy goal
+ create healthyDietGoal
+ Parser -> healthyDietGoal++ : HealthyDietGoal()
+ healthyDietGoal --> Parser-- : :HealthyDietGoal
+ else is unhealthy goal
+ create unhealthyDietGoal
+ Parser -> unhealthyDietGoal++ : UnhealthyDietGoal()
+ unhealthyDietGoal --> Parser-- : :DietGoal
+ end
+ end
+
+Parser --> Parser-- : temp:DietGoalList
+create SetDietGoalCommand
+Parser -> SetDietGoalCommand++ : SetDietGoalCommand()
+SetDietGoalCommand --> Parser-- : :SetDietGoalCommand
+Parser --> AthletiCLI-- : :SetDietGoalCommand
+AthletiCLI -> SetDietGoalCommand++ : execute()
+SetDietGoalCommand -> dataData++ : getDietGoals()
+dataData --> SetDietGoalCommand-- : data:DietGoalList
+
+ loop number of valid new healthy and unhealthy goals
+ SetDietGoalCommand -> dataDietGoalList++ : add()
+
+ dataDietGoalList --
+
+
+ end
+
+destroy tempDietGoalList
+SetDietGoalCommand --> AthletiCLI-- : messages:String
+
+destroy SetDietGoalCommand
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Diet/EditDietSequenceDiagram.puml b/docs/puml/Diet/EditDietSequenceDiagram.puml
new file mode 100644
index 0000000000..bbffec9aba
--- /dev/null
+++ b/docs/puml/Diet/EditDietSequenceDiagram.puml
@@ -0,0 +1,42 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+
+!define LOGIC_COLOR #3333C4
+
+participant ":AthletiCLI" as AthletiCLI LOGIC_COLOR
+participant "Parser" as Parser <> #lightblue
+participant "DietParser" as DietParser <> #lightblue
+participant "c:EditDietCommand" as EditDietCommand #lightgreen
+participant "data:Data" as Data #lightgrey
+participant "diets:DietList" as DietList #lightgrey
+participant "oldDiet:Diet" as oldDiet #yellow
+
+AthletiCLI++
+AthletiCLI -> Parser++: parseCommand(userInput)
+Parser -> DietParser++: parseDietEdit(arguments)
+DietParser --> Parser: dietMap
+DietParser--
+Parser -> EditDietCommand++: new EditDietCommand(index, dietMap)
+EditDietCommand --> Parser--: c
+Parser --> AthletiCLI--: c
+
+AthletiCLI -> EditDietCommand++: execute(data)
+EditDietCommand -> Data++: getDiets()
+Data --> EditDietCommand--: diets
+EditDietCommand -> DietList++: get(index - 1)
+DietList --> EditDietCommand--: oldDiet
+
+loop for each key in dietMap
+ EditDietCommand -> oldDiet++ : set[key](value)
+ oldDiet --> EditDietCommand--
+end
+
+
+EditDietCommand -> DietList++: set(index - 1, oldDiet)
+DietList --> EditDietCommand--
+EditDietCommand --> AthletiCLI--: message
+
+destroy EditDietCommand
+@enduml
diff --git a/docs/puml/General/DataClassDiagram.puml b/docs/puml/General/DataClassDiagram.puml
new file mode 100644
index 0000000000..514c4dc4b9
--- /dev/null
+++ b/docs/puml/General/DataClassDiagram.puml
@@ -0,0 +1,77 @@
+@startuml
+'https://plantuml.com/class-diagram
+skinparam classAttributeIconSize 0
+hide circle
+
+abstract class "StorableList"{
+ - path: String
+ + StorableList(path: String): StorableList
+ + load()
+ + save()
+ + {abstract} parse(s:String)
+ + {abstract} unparse(t:T)
+
+}
+
+interface "<>\nFindable" {
+ + find(date: LocalDate): ArrayList
+}
+class Data{
+ + getInstance():Data
+ + load(): void
+ + save(): void
+ + clear(): void
+}
+class ActivityList{
+ + find(date: LocalDate): ArrayList
+ + parse(s:String)
+ + unparse(t:T)
+}
+class DietList{
++ find(date: LocalDate): ArrayList
+ + parse(s:String)
+ + unparse(t:T)
+}
+class SleepList{
++ find(date: LocalDate): ArrayList
+ + parse(s:String)
+ + unparse(t:T)
+}
+
+class ActivityGoalList{
+ + parse(s:String)
+ + unparse(t:T)
+}
+class DietGoalList{
+ + parse(s:String)
+ + unparse(t:T)
+}
+class SleepGoalList{
+ + parse(s:String)
+ + unparse(t:T)
+}
+
+
+"<>\nFindable" <|.. ActivityList
+"<>\nFindable" <|.. DietList
+"<>\nFindable" <|.. SleepList
+
+"StorableList" <|-- ActivityList
+"StorableList" <|-- DietList
+"StorableList" <|-- SleepList
+"StorableList" <|-- ActivityGoalList
+"StorableList" <|-- DietGoalList
+"StorableList" <|-- SleepGoalList
+
+Data "1" --u- "1" ActivityList : contains >
+Data "1" --u- "1 " DietList : contains >
+Data "1" --u- "1" SleepList : contains >
+Data "1" --u- "1" ActivityGoalList : contains >
+Data "1 " --u- "1" DietGoalList : contains >
+Data "1" --u- "1" SleepGoalList : contains >
+
+
+
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/General/MainClassDiagram.puml b/docs/puml/General/MainClassDiagram.puml
new file mode 100644
index 0000000000..4754586413
--- /dev/null
+++ b/docs/puml/General/MainClassDiagram.puml
@@ -0,0 +1,70 @@
+@startuml
+'https://plantuml.com/class-diagram
+skinparam classAttributeIconSize 0
+hide circle
+
+class AthletiCLI{
+ -logger:Logger
+ -ui:Ui
+ -data:Data
+ -runSaveCommand:Thread
+ -AthletiCLI(): void
+ -run(): void
+ +main(): void
+
+}
+class Ui{
+ - uiInstance: Ui
+ - in: Scanner
+ - out: PrintStream
+ - Ui(): Ui
+ + getInstance(): Ui
+ + getUserCommand(): String
+ + showMessages(messages: String): void
+ + showException(e: Exception): void
+ + showWelcome(): void
+
+}
+class Parser{
+ - INVALID_YEAR: String
+ + splitCommandWordAndArgs(rawUserInput: String): String[]
+ + parseCommand(rawUserInput: String):Command
+ + parseDateTime(datetime: String): LocalDateTime
+ + parseDate(date: String): LocalDate
+ + parseNonNegativeInteger(integer:String, invalidMessage: String, overflowMessage: String): int
+ + getValueForMarker(arguments: String, marker: String): String
+
+}
+class Data{
+ - dataInstance: Data
+ - activities: ActivityList
+ - activityGoals: ActivityGoalList
+ - diets: DietList
+ - dietGoals: DietGoalList
+ - sleeps: SleepList
+ - sleepGoals: SleepGoalList
+ + getInstance():Data
+ + load(): void
+ + save(): void
+ + clear(): void
+ + getActivities(): ActivityList
+ + getActivityGoalList(): ActivityGoalList
+ + getDiets():DietList
+ + getDietGoals(): DietGoalList
+ + getSleeps(): SleepList
+ + getSleepGoals(): SleepGoalList
+ + setActivities(activities: ActivityList): void
+ + setActivityGoalList(activityGoals: ActivityGoalList): void
+ + setDiets(diets: DietList): void
+ + setDietGoals(dietGoals: DietGoalList): void
+ + setSleeps(sleeps: SleepList): void
+ + setSleepGoals(sleepGoals: SleepGoalList): void
+
+}
+
+
+
+AthletiCLI "1" --> "1" Ui : sends display message to >
+AthletiCLI "1" --> "1" Parser : sends user command to >
+AthletiCLI "1" --> "1" Data : saves data to >
+@enduml
\ No newline at end of file
diff --git a/docs/puml/General/ParserClassDiagram.puml b/docs/puml/General/ParserClassDiagram.puml
new file mode 100644
index 0000000000..8860d97a9f
--- /dev/null
+++ b/docs/puml/General/ParserClassDiagram.puml
@@ -0,0 +1,31 @@
+@startuml
+'https://plantuml.com/class-diagram
+hide circle
+
+class Parser {
+ parseCommand(rawUserInput: String): Command
+ parseDateTime(datetime: String): LocalDateTime
+ parseDate(date: String): LocalDate
+}
+
+class SleepParser {}
+class ActivityParser {}
+class DietParser {}
+
+abstract class Command {
+ {abstract} execute(data: Data): String[]
+}
+
+class Parameter {}
+class Message {}
+class AthletiException {}
+
+Parser ..> Command : returns
+Parser --> AthletiException : throws
+Parser ..> SleepParser : uses
+Parser ..> ActivityParser : uses
+Parser ..> DietParser : uses
+Parser ..> Parameter : uses
+Parser ..> Message : uses
+
+@enduml
diff --git a/docs/puml/HelpAddDiet.puml b/docs/puml/HelpAddDiet.puml
new file mode 100644
index 0000000000..c876f2d0dd
--- /dev/null
+++ b/docs/puml/HelpAddDiet.puml
@@ -0,0 +1,29 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+participant ":AthletiCLI" as AthletiCLI #lightblue
+participant "<>\nParser" as Parser #lightgreen
+participant ":HelpCommand" as HelpCommand #lightpink
+participant ":Ui" as Ui #lightyellow
+actor User as User
+
+
+'autonumber
+AthletiCLI++
+AthletiCLI -> Ui++ : getUserCommand()
+User -> Ui : "help add-diet"
+Ui --> AthletiCLI-- : "help add-diet"
+AthletiCLI -> Parser++ : parseCommand("help add-diet")
+create HelpCommand
+Parser -> HelpCommand++ : new HelpCommand("add-diet")
+HelpCommand --> Parser-- : :HelpCommand
+Parser --> AthletiCLI-- : :HelpCommand
+AthletiCLI -> HelpCommand++ : execute(data)
+HelpCommand --> AthletiCLI-- : feedback:String
+AthletiCLI -> Ui++ : showMessages(feedback)
+Ui --> AthletiCLI--
+
+destroy HelpCommand
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Save.puml b/docs/puml/Save.puml
new file mode 100644
index 0000000000..7234ba3147
--- /dev/null
+++ b/docs/puml/Save.puml
@@ -0,0 +1,20 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+participant ":SaveCommand" as SaveCommand
+participant ":Data" as Data #lightblue
+participant ":StorableList" as StorableList #lightgreen
+participant "<>\nStorage" as Storage #lightpink
+
+
+'autonumber
+SaveCommand -> Data++ : save()
+Data -> StorableList++ : save()
+StorableList -> Storage++ : save(path, items)
+Storage --> StorableList--
+StorableList --> Data--
+ref over Data : Save other lists
+Data --> SaveCommand
+
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Sleep/SleepAndSleeplistClassDiagram.puml b/docs/puml/Sleep/SleepAndSleeplistClassDiagram.puml
new file mode 100644
index 0000000000..50b6df56d9
--- /dev/null
+++ b/docs/puml/Sleep/SleepAndSleeplistClassDiagram.puml
@@ -0,0 +1,50 @@
+@startuml
+'https://plantuml.com/class-diagram
+skinparam classAttributeIconSize 0
+hide circle
+
+
+interface Findable<> {
+ + find(date: LocalDate): ArrayList
+}
+
+abstract class StorableList {
+ - path: String
+ + save()
+ + load()
+ + {abstract} parse(s: String): T
+ + {abstract} unparse(t: T): String
+}
+
+
+class Sleep {
+ - startDateTime: LocalDateTime
+ - endDateTime: LocalDateTime
+ - sleepingDuration: Duration
+ - sleepDate: LocalDate
+
+ + Sleep(startDateTime: LocalDateTime, toDateTime: LocalDateTime)
+ + getStartDateTime(): LocalDateTime
+ + getEndDateTime(): LocalDateTime
+ + getSleepDate(): LocalDate
+ + getSleepingTime(): LocalTime
+ + toString(): String
+
+ - calculateSleepingDuration(): Duration
+ - calculateSleepDate(): LocalDate
+ - generateSleepingDurationStringOutput(): String
+ - generateStartDateTimeStringOutput(): String
+ - generateEndDateTimeStringOutput(): String
+ - generateSleepDateStringOutput(): String
+}
+
+class SleepList {
+ + sort()
+ + filterByTimespan(timeSpan: Goal.TimeSpan): ArrayList
+ + getTotalSleepDuration(timeSpan: Goal.TimeSpan): int
+}
+
+SleepList --|> StorableList: extends
+SleepList "1" o-l- "*" Sleep :contains >
+SleepList ..|> Findable : implements
+@enduml
\ No newline at end of file
diff --git a/docs/puml/Sleep/SleepObjectSequenceDiagram.puml b/docs/puml/Sleep/SleepObjectSequenceDiagram.puml
new file mode 100644
index 0000000000..b2de3c081a
--- /dev/null
+++ b/docs/puml/Sleep/SleepObjectSequenceDiagram.puml
@@ -0,0 +1,46 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+skinparam Style strictuml
+skinparam SequenceMessageAlignment center
+
+!define LOGIC_COLOR #3333C4
+
+participant ":AthletiCLI" as AthletiCLI #orange
+participant "Parser" as Parser <> #lightblue
+participant "SleepParser" as SleepParser <> #lightblue
+participant "s:Sleep" as Sleep #yellow
+participant "sleepDuration:Duration" as duration #gold
+participant "c:EditSleepCommand" as EditSleepCommand #lightgreen
+participant "data:Data" as Data #lightgrey
+participant "sleeps:SleepList" as sleeps #lightgrey
+
+
+AthletiCLI++
+AthletiCLI->Parser++: parseCommand(input)
+
+Parser -> SleepParser++: parseSleep(arguments)
+Parser -> SleepParser++: parseSleepIndex(arguments)
+deactivate SleepParser
+
+SleepParser -> Sleep++: Sleep()
+
+Sleep --> duration++: calculateSleepDuration()
+duration --> Sleep--: SleepDuration
+Sleep --> SleepParser--: s
+SleepParser --> Parser--: s
+
+Parser -> EditSleepCommand++: EditSleepCommand(index, s)
+EditSleepCommand --> Parser--: c
+Parser --> AthletiCLI--: c
+
+AthletiCLI -> EditSleepCommand++: execute(s, data)
+EditSleepCommand -> Data++: getSleeps()
+
+
+Data --> EditSleepCommand--: sleeps
+EditSleepCommand -> sleeps++: setSleep(index, s)
+sleeps --> EditSleepCommand--
+EditSleepCommand --> AthletiCLI--: message
+
+destroy EditSleepCommand
+@enduml
\ No newline at end of file
diff --git a/docs/puml/architectureDiagram.puml b/docs/puml/architectureDiagram.puml
new file mode 100644
index 0000000000..5280ec691d
--- /dev/null
+++ b/docs/puml/architectureDiagram.puml
@@ -0,0 +1,39 @@
+@startuml
+'https://plantuml.com/class-diagram
+'!include style.puml
+hide footbox
+
+actor User
+'box #white
+'frame ""f"
+'participant user2
+'participant AthletiCLI
+'participant Ui
+'participant Parser
+'participant Data
+'participant Storage
+'participant Commands
+frame "AthletiCLI App"{
+rectangle AthletiCLI
+rectangle Ui
+rectangle Parser
+rectangle Data
+rectangle Storage
+rectangle Commands
+'end rectangle
+
+}
+'end frame
+'end box
+
+User -d-> Ui
+Ui -r-> AthletiCLI
+AthletiCLI -d-> Parser
+AthletiCLI -d-> Commands
+AthletiCLI -d-> Data
+Commands -u-> Data
+Parser -r-> Data
+Data -d-> Storage
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/team/alwo223.md b/docs/team/alwo223.md
new file mode 100644
index 0000000000..ed7ed08bc7
--- /dev/null
+++ b/docs/team/alwo223.md
@@ -0,0 +1,79 @@
+---
+layout: page
+title: Alexander Wolters’ Portfolio
+---
+
+## Project: AthletiCLI
+
+**AthletiCLI** is a Java-based application designed for dedicated athletes to track, analyse, and optimize their athletic
+performance. This tool not only monitors physical activities but also dietary habits,
+sleep metrics, and more. The user interacts through a user-friendly CLI. The project comprises about 11 kLoC.
+
+View my **code contributions** on [RepoSense](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?
+search=alwo223&breakdown=true). The key enhancements are summarized below.
+
+#### New Features
+ * **Added the ability to add, list and delete activities**
+ * Purpose: This feature is the core of activity management as it enables users to track their athletic
+ performance and progress.
+ * Highlights: Implementing an elegant, efficient and unified solution for the different activity types with
+ unique parameters and commands was a complex challenge. This was achieved by leveraging inheritance, generic
+ parser functions and extensive refactoring leading to a modular and efficient design. Therefore, this approach involved in-depth analysis and planning.
+ * **Added command to list all activities**
+ * Purpose: This feature allows users to view their activities chronologically and in different levels of detail,
+ aiding in performance analysis and progress tracking.
+ * Highlights: The implementation included a sorting mechanism by date and time and ensured data consistency
+ during any data modifying operations.
+ * **Added command to effortlessly edit activities**
+ * Purpose: This feature is essential for users to correct or update their activities without
+ replacing the whole entry, thus enhancing the user experience.
+ * Highlights: Similar to the add command, this feature required a modular implementation approach to handle the
+ different activity and to effectively reuse existing parser functions.
+ * **Implemented parsing and unparsing functionality for activity (goal) storing**
+ * Purpose: This features allows to store all activities and activity goals in a file and parse them on startup
+ of the application. This feature improves the product significantly by enabling to close and reopen the
+ application without any data loss.
+ * Highlights: The approach was developed in collaboration with @nihalzp. The storing functionality of other
+ tracking components like sleep were based on this implementation. It involved some analysis of the existing code
+ to efficiently reuse existing parser functions.
+ * **Implemented goal tracking mechanism and find feature for activities**
+ * Purpose: empowers users to set and monitor goals for different periods, sports and metrics. It is essential
+ for the user to plan their training and to push themselves to improve.
+ This also comes with the ability to find activities by date.
+ * Highlights: The implementation was adopted for other goal tracking mechanism like sleep and diet.
+
+#### Review / Mentoring
+* [Reviewed PRs](https://github.com/AY2324S1-CS2113-T17-1/tp/issues?q=reviewed-by%3Aalwo223+) (examples:
+[#288](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/288),
+[#280](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/280),
+[#95](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/95),
+[#21](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/21))
+* [Issues reported / discussed](https://github.com/AY2324S1-CS2113-T17-1/tp/issues?q=author%3Aalwo223+type%3Aissue)
+* [Discussions in forum](https://github.com/AY2324S1-CS2113-T17-1/tp/discussions/110)
+
+#### Project Management
+* Set up the GitHub repository and team organization for the project.
+* Maintained issue tracker, including generating suitable labels.
+* Responsible for ensuring proper testing of the implemented features.
+* Managed final release v2.1.
+* Strictly following deadlines, git conventions and forking workflow.
+
+#### Documentation
+* User Guide:
+ * Added documentation for the features `add-activity`, `add-run`, `add-swim`, `add-cycle`, `delete-activity`,
+ `list-activity`, `edit-activity`, `edit-run`, `edit-cycle`, `edit-swim`, `set-activity-goal`: [Activity
+ Management](../UserGuide.html#-activity-management)
+ * Improved overall visual appearance of the document: [#253](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/253)
+* Developer Guide:
+ * Explained all implementation details in DG related to Activity Management, including `add-activity` and
+ `set-activity-goal` features, find by timespan, goal tracking mechanism, detailed parsing process, modular
+ implementation approach and justification: [Activity Management](../DeveloperGuide.html#activity-management-in-athleticli)
+ * Created UML diagrams: [#1](../images/ActivityInheritance.svg),
+ [#2](../images/ActivityGoalEvaluation.svg),
+ [#3](../images/ActivityObjectDiagram.svg), [#4](../images/ActivityParsing.svg),
+ [#5](../images/AddActivity.svg), [#6](../images/AddActivityGoal.svg)
+ * Provided test instructions for activity related features
+
+#### Community
+* PRs reviewed (with non-trivial review comments): [#139](https://github.com/nus-cs2113-AY2324S1/tp/pull/8#pullrequestreview-1709775159), [tp comments dashboard](https://nus-cs2113-ay2324s1.github.io/dashboards/contents/tp-comments.html)
+* Reported bugs and suggestions for other teams in the class: [#139](https://github.com/nus-cs2113-AY2324S1/tp/pull/8#pullrequestreview-1709775159), [Issues created](https://github.com/AY2324S1-CS2113-W12-3/tp/issues?q=%22%5BPE-D%5D%5BTester+A%5D%22)
diff --git a/docs/team/dadevchia.md b/docs/team/dadevchia.md
new file mode 100644
index 0000000000..e2a0c56e7f
--- /dev/null
+++ b/docs/team/dadevchia.md
@@ -0,0 +1,77 @@
+---
+layout: page
+title: Dylan Chia's Project Portfolio Page (PPP)
+---
+
+# Project: AthletiCLI
+
+## Overview
+Contributed to all sleep related features, including the `sleep` commands, `Sleep` class, `SleepParser` class, as well as the `SleepGoal` class.
+
+Also contributed to the formatting of the `User Guide` including the `Command Summary` and `FAQ`.
+
+View my **code contributions** on [RepoSense](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?
+search=dadevchia&breakdown=true).
+
+## Summary of Contributions
+Given below are my contributions to the project.
+
+### New Feature: Added the ability to add, edit, delete and list sleep
+
+* What it does: Allows the user to track their sleep by adding, editing, deleting and listing sleep.
+* Justification: This feature is the core of the sleep management as it allows the user to track their sleep.
+* Highlights: It was challenging to find an elegant and efficient implementation which keeps code redundancy to a minimum. I used inheritance to create a parent class for sleep, and child classes for different types of sleep. This allowed for a modular implementation, which was easy to understand and extend. I also used a custom parser to parse the sleep entries, which allowed for a more efficient implementation.
+
+### New Feature: Added the ability to find sleep by date
+
+* What it does: Allows the user to find sleep by date.
+* Justification: This feature allows the user to find sleep entries by date, which is useful for analysing sleep performance.
+* Highlights: The implementation had to be done in a way that was consistent with the other find commands. The difficulty was that sleep records do not have a fixed date, but rather a start and end datetime, which had to be accounted for. I used a custom constructor to analyze the datetime and create a sleep entry with the correct date.
+
+### New Feature: Added the ability to list all sleep records
+
+* What it does: Allows the user to list all sleep records, including the sleep start and end datetime, and duration of sleep.
+* Justification: This feature allows the user to view their sleep records chronologically and have automated calculations of the duration of sleep.
+* Highlights: The sleep duration had to be calculated using the start and end datetime, which was a unique implementation from other classes. I used the Duration class from Java to store the duration of sleep, which can be calculated and tracked easily.
+
+### New Feature: Added sleep goal tracking mechanism
+* What it does: Allows the user to set a sleep goal and track their progress towards the goal of number of minutes slept, in the past day, week, month or year.
+* Justification: This feature allows the user to compare their sleep performance and analyse their progress over time.
+* Highlights: The implementation had many different parameters and OOP concepts, which had to be applied during any target modifying operations. Duration of sleep was also a unique implementation that had to be accounted for. I used the Duration class from Java to store the duration of sleep, which can be calculated and tracked easily.
+
+
+### New Feature: Implemented storing capabilities for sleep and sleep goals
+* What it does: automatically stores all sleep and sleep goals in a file and loads them on startup of the application. It also allows for the user to edit the file manually.
+* Justification: This feature improves the product significantly by allowing the user to close the application and reopen it without losing any data. This is especially important as the application is designed to track the progress over a longer period of time. It also allows for the user to edit the file manually, which is useful for manual data entry.
+* Highlights: The implementation had issues with the parser and the storage of sleep entries. A custom parser was created to parse the sleep entries, and the storage of sleep entries was done using a custom storage class. The storage class was also used to store sleep goals.
+
+
+#### Review
+* [Reviewed PRs](https://github.com/AY2324S1-CS2113-T17-1/tp/issues?q=reviewed-by:dadevchia+) (Examples: [#31](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/31) [#118](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/118) )
+
+* [Started Discussions in Github Forum](https://github.com/AY2324S1-CS2113-T17-1/tp/discussions/49)
+
+* [Issues reported / discussed](https://github.com/AY2324S1-CS2113-T17-1/tp/issues?q=author:dadevchia+type:issue)
+
+### Code Contributed
+[RepoSense Link](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=dadevchia&breakdown=true)
+
+### Project Management
+* Maintained issue tracker, including generating suitable labels.
+* Responsible for ensuring proper testing of the implemented features.
+* Planned and led group meetings, ensuring that a clear direction was set for the project.
+* Managed release v1.0 and v2.0.
+* Strictly following deadlines, git conventions and forking workflow.
+
+### Documentation
+* User Guide:
+ * Added documentation for the features `add-sleep`, `delete-sleep`, `edit-sleep` `list-sleep`, `edit-sleep`, `find-sleep`, `set-sleep-goal`, `list-sleep-goal`, `edit-sleep-goal`
+ * Added the `Command Summary` and `FAQ` sections
+
+* Developer Guide:
+ * Explained implementation details of the sleep commands, including `add-sleep`, `delete-sleep`, `edit-sleep` `list-sleep`, `edit-sleep`, `find-sleep`,
+ * Explained how the parser works for sleep commands with an assosciated UML sequence diagram
+ * Explained how the sleep object links to assosciated classes with an UML class diagram
+ * Explained challenges and how they were overcome, particularly with regards to the duration of sleep
+ * Added Value Proposition and User Stories
+ * Provided test instructions for sleep commands
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index ab75b391b8..0000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# John Doe - Project Portfolio Page
-
-## Overview
-
-
-### Summary of Contributions
diff --git a/docs/team/nihalzp.md b/docs/team/nihalzp.md
new file mode 100644
index 0000000000..29e5f03b15
--- /dev/null
+++ b/docs/team/nihalzp.md
@@ -0,0 +1,57 @@
+---
+layout: page
+title: Nihal Parash's Project Portfolio Page
+---
+
+# Project: AthletiCLI
+
+## Overview
+
+**AthletiCLI** is your all-in-one solution to track, analyse, and optimize your athletic performance. Designed for the
+committed athlete, this command-line interface (CLI) tool not only keeps tabs on your physical activities but also
+covers dietary habits, sleep metrics, and more.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+### Code Contributed
+
+[RepoSense Link](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=nihalzp&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code&since=2023-09-22&tabOpen=true&tabType=authorship&tabAuthor=nihalzp&tabRepo=AY2324S1-CS2113-T17-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+### Features:
+
+* **Diet Record Management**: Designed and implemented the adding, deleting, editing, listing, and finding of diet
+ records.
+* **Activity Goal Management**: Designed and implemented the deleting, editing, and listing of activity goals.
+* **Common Parsing Functions**: Enhanced and refactored widely used `getValueForMarker`, `parseDateTime` and
+ `parseDate` functions to make them more robust and reusable.
+* **Enhancements:**
+ - Enhanced the `add-diet` feature, enabling the input of various data fields such as `calories`, `fat`, `carb`,
+ `protein`, `datetime` in any order.
+ - Refined the `edit-diet` feature, allowing users to modify necessary data fields without altering the remaining data.
+
+### Project Management
+
+* Implemented features across versions 1.0, 2.0, and 2.1 incrementally, aligning with development plans.
+* Utilized forking and branching for parallel development and seamless feature integration.
+* Managed bugs effectively using issue tracking, improving project accuracy and reliability.
+* Organized issue tracking by updating labels and assigning tasks, enhancing team efficiency.
+
+### Documentation
+* **User Guide:**
+ * Added documentation for the features `add-diet`, `edit-diet`, `delete-diet`, `list-diet`, `find-diet`,
+ `edit-activity-goal`, `delete-activity-goal`, `list-activity-goal`.
+ * Updated the `Command Summary`, `User Stories` sections regularly.
+* **Developer Guide:**
+ * Explained the implementation structure of adding, editing, deleting, listing and finding diets.
+ * Outlined the implementation idea for editing, deleting, and listing activity goals.
+ * Created UML diagrams:
+ - `Parser` class diagram
+ - `edit-diet` command sequence diagram
+ * Provided test instructions for diet record management and activity goal management.
+
+#### Community
+* Reviewed 24 PRs. [PRs I commented on](https://github.com/AY2324S1-CS2113-T17-1/tp/pulls?q=commenter%3Anihalzp+is%3Apr+-author%3Anihalzp)
+* Issues reported for other teams:
+ * [PE Dry Run](https://github.com/AY2324S1-CS2113-W12-4/tp/issues?q=%5BPE-D%5D%5BTester+E%5D+)
\ No newline at end of file
diff --git a/docs/team/photo/yicheng-toh.png b/docs/team/photo/yicheng-toh.png
new file mode 100644
index 0000000000..4d0ef76829
Binary files /dev/null and b/docs/team/photo/yicheng-toh.png differ
diff --git a/docs/team/skylee03.md b/docs/team/skylee03.md
new file mode 100644
index 0000000000..53e5aaeae1
--- /dev/null
+++ b/docs/team/skylee03.md
@@ -0,0 +1,45 @@
+---
+layout: page
+title: Ming-Tian’s Portfolio
+---
+
+## Overview
+
+**AthletiCLI** is your all-in-one solution to track, analyse, and optimize your athletic performance. Designed for the committed athlete, this command-line interface (CLI) tool not only keeps tabs on your physical activities but also covers dietary habits, sleep metrics, and more.
+
+## Summary of Contributions
+
+Given below are my contributions to the project.
+
+* :computer: **Code contributed**: [RepoSense link](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code&since=2023-09-22&tabOpen=true&tabType=authorship&tabAuthor=skylee03&tabRepo=AY2324S1-CS2113-T17-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+* :house: **Architecture**: Designed the overall software architecture of AthletiCLI.
+* :bulb: **Features**:
+ * **Entry**: Designed and implemented the `AthletiCLI` class as the entry component of the program.
+ * **UI**: Designed and implemented the `Ui` class which provides the basic interactive functions.
+ * **Commands**: Designed and implemented the `Command` abstract class as the prototype of any other commands. Designed and implemented the `ByeCommand`, the `FindCommand`, the `HelpCommand`, and the `SaveCommand`.
+ * **Data**: Designed and implemented the `Data` class which serves as the core component of data processing.
+ * **Retrieval of Entries**: Designed and implemented the `Findable` interface which is an abstraction to lists whose entries can be retrieved with a keyword.
+ * **Goals**: Designed and implemented the `Goal` abstract class in which the basic attributes (e.g., time span) and methods of a goal.
+ * **File Storage**: Designed and implemented the `Storage` class and the `StorableList` abstract class. The former provides underlying file reading and writing functions, and the latter is an abstraction to lists which can be converted into a stream to be used for file reading and writing.
+ * **Exception Handling**: Designed and implemented the `AthletiCLI` class and some exception wrappers.
+* :cop: **Project management**:
+ * Develops the project iteratively and incrementally.
+ * Manages our project using GitHub mechanisms: milestones, releases, issues, PRs, etc.
+ * Strictly adheres to the [schedule](https://nus-cs2113-ay2324s1.github.io/website/schedule/timeline.html).
+ * Strictly follows our [Git conventions](https://se-education.org/guides/conventions/git.html).
+ * Strictly follows the [forking workflow](https://nus-cs2113-ay2324s1.github.io/website/se-book-adapted/chapters/gitAndGithub.html#forking-workflow).
+* :books: **Documentation**:
+ * Integrated a Jekyll theme ([Alembic](https://github.com/daviddarnes/alembic)) to the project website.
+ * Integrated a Jekyll plugin ([Jemoji](https://github.com/jekyll/jemoji)) to the project website.
+ * :green_book: User Guide:
+ * Added instructions on [miscellaneous commands](../UserGuide.html#miscellaneous).
+ * :blue_book: Developer Guide:
+ * Contributed to the sections of [design](../DeveloperGuide.html#design) and [implementation](../DeveloperGuide.html#implementation).
+ * Added sequence diagrams for [`help add-diet`](../images/HelpAddDiet.svg) and [`save`](../images/Save.svg).
+ * Checked and unified the format of the DG.
+* :family: **Community**:
+ * :eyes: Reviewed PRs: [tP comments dashboard](https://nus-cs2113-ay2324s1.github.io/dashboards/contents/tp-comments.html)
+ * :lips: Contributed to forum discussions: [Forum activities dashboard](https://nus-cs2113-ay2324s1.github.io/dashboards/contents/forum-activities.html)
+ * :open_hands: Reported bugs and suggestions for other teams in the class:
+ * [Issues I created](https://github.com/AY2324S1-CS2113-T18-1/tp/issues?q=%5BPE-D%5D%5BTester+E%5D)
+ * [Issues/PRs I commented on](https://github.com/AY2324S1-CS2113-T18-1/tp/issues?q=involves%3Askylee03)
\ No newline at end of file
diff --git a/docs/team/yicheng-toh.md b/docs/team/yicheng-toh.md
new file mode 100644
index 0000000000..87cdf35339
--- /dev/null
+++ b/docs/team/yicheng-toh.md
@@ -0,0 +1,109 @@
+---
+layout: page
+title: Toh Yi Cheng - Project Portfolio Page
+---
+
+# Project: AthletiCLI
+
+## Overview
+
+**AthletiCLI** is an application used to track, analyse, and optimize the users athletic performance.
+It is designed for committed athletes who not only keep track of their physical activities but also dietary habits,
+sleep metrics, and more. The user interacts with it using a CLI. It is written in Java, and has more than 10k LoC.
+
+## Summary of Contributions
+
+### Code contributed:
+
+* Code contributed: [RepoSense Link](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code&since=2023-09-22&tabOpen=true&tabType=authorship&tabAuthor=yicheng-toh&tabRepo=AY2324S1-CS2113-T17-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false)
+
+### Feature implemented
+
+#### New feature: Users can add and delete diet goals
+
+For motivated users on AthletiCLI, they can create diet goals to keep track of their nutrient intake.
+The nutrients supported currently are Calories, Fat, Carb and Protein. Consuming more nutrient than the
+target value indicates that they have achieved their diet goal for that specific nutrient.
+
+If they would like to remove their existing goals, they can remvoe it with the delete function
+
+#### New feature: Users can see all diet goals
+
+This provides a convenient way for users to see all the diet goals that they have created and their current progress.
+
+#### New feature: Editing diet goals
+
+Instead of deleting diet goals and creating a new one, edit diet goal functionality hopes to streamline the process.
+Instead of typing 2 commands to edit the target value of users' current diet goals, one command could
+do the same trick.
+
+### Enhancements implemented:
+
+#### Enhancement: Diet goal tracks diets within a limited time period. Daily and Weekly.
+
+With the enhancement of diet goals, instead of tracking infinite records of diets in the past, the diet goal is
+now optimised with controlled time span of 1 day (daily diet goal) or 7 days (weekly diet goal). This enhancement
+provides more meaningful diet goal function for the users to track their nutrients intake from their diets.
+
+This explains the use of daily/weekly in setting and editing diet goal commands.
+
+**Example of set diet goal command:** `set-diet-goal DAILY calories/500`
+
+#### Enhancement: Diet goal not only encourages nutrients intake but also discourages nutrients intake.
+
+Previously, users can only set diet goals that keep track of their nutrient intake. Once they have exceeded their
+target value for the nutrients, the diet goals is marked as achieved.
+
+However, this may not be the case for all nutrients.
+For example, for athletes who want to gain muscles, they would increase their intake of protein. At the same time,
+they would need to reduce their weight by cutting on fat consumption.
+In this case, the diet goal only encourage them to consume more fat.
+Therefore, 'unhealthy' diet goal is created. It marks a diet goal as not achieved if the value consumed is greater
+than the target value.
+
+The creation of such goal can be accomplished by indicating an optional flag `unhealthy`.
+
+**Example of set diet goal command:** `set-diet-goal DAILY unhealthy calories/500`
+
+
+### Contributions to the UG:
+
+* Contributed to Activities section of AthlethiCLI for UG draft.
+* Contributed to Diet Goals section of AthlethiCLI for UG which includes `set-diet-goal`,
+`edit-diet-goal`, `list-diet-goal`, `delete-diet-goal`.
+* Contributed to the FAQ section of UG.
+
+### Contributions to the DG:
+
+#### Sections contributed:
+* Setting up of diet goals
+
+#### Added UML diagrams:
+
+Class Diagram for AthletiCLI main class:
+![](../images/MainClassDiagram.svg)
+
+Class Diagram for data class:
+![](../images/DataClassDiagram.svg)
+
+Sequence diagram for creating a diet goal:
+![](../images/DietGoalsSequenceDiagram.svg)
+
+### Contributions to team-based tasks
+
+* Setup approval system for team's GitHub page so that PR gets reviewed before merging.
+* Kept track of deadlines for v1.0 and v2.0.
+* Assisted in sorting and assigning of post PE dry run issues.
+* Suggested the use of interface for find function and abstract class for goals.
+This is only implemented due to [skylee03 (Ming-Tian)](./skylee03.html)'s outstanding effort in convincing the team.
+* Examples of PR reviewed:
+ * [PR for editing activities](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/59#discussion_r1362968136)
+ * [PR for assertions and logging](https://github.com/AY2324S1-CS2113-T17-1/tp/pull/44#discussion_r1361460286)
+* Created issues labels: `type.Optimization`, `UG`, `DG` to facilitate effective classification.
+
+### Contributions beyond the project team
+
+* PE dry Run:
+ * [Screenshot captured during PE dry run](https://github.com/yicheng-toh/ped/tree/main/files)
+* DG review for other teams:
+ * [SysLib CLI](https://github.com/nus-cs2113-AY2324S1/tp/pull/6), [Fit Track](https://github.com/nus-cs2113-AY2324S1/tp/pull/13), [FITNUS](https://github.com/nus-cs2113-AY2324S1/tp/pull/27)
diff --git a/src/main/java/athleticli/AthletiCLI.java b/src/main/java/athleticli/AthletiCLI.java
new file mode 100644
index 0000000000..ca04acd5fb
--- /dev/null
+++ b/src/main/java/athleticli/AthletiCLI.java
@@ -0,0 +1,91 @@
+package athleticli;
+
+import java.io.IOException;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.FileHandler;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import athleticli.commands.Command;
+import athleticli.commands.SaveCommand;
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+import athleticli.parser.Parser;
+import athleticli.ui.Ui;
+
+/**
+ * Defines the basic structure and the behavior of AthletiCLI.
+ */
+public class AthletiCLI {
+ private static Logger logger = Logger.getLogger(AthletiCLI.class.getName());
+ private static Ui ui = Ui.getInstance();
+ private static Data data = Data.getInstance();
+
+ private static Thread runSaveCommand = new Thread(() -> {
+ try {
+ final String[] feedback = new SaveCommand().execute(data);
+ ui.showMessages(feedback);
+ } catch (AthletiException e) {
+ ui.showException(e);
+ }
+ });
+
+ /**
+ * Constructs an AthletiCLI object.
+ */
+ private AthletiCLI() {
+ LogManager.getLogManager().reset();
+ try {
+ logger.addHandler(new FileHandler("%t/athleticli-log.txt"));
+ } catch(IOException e) {
+ logger.addHandler(new ConsoleHandler());
+ }
+ }
+
+ /**
+ * Creates an `AthletiCLI` object and runs it.
+ *
+ * @param args Arguments obtained from the command line.
+ */
+ public static void main(String[] args) {
+ new AthletiCLI().run();
+ }
+
+ /**
+ * Displays the welcome interface, continuously reads user input
+ * and executes corresponding instructions until exiting.
+ */
+ private void run() {
+ logger.entering(getClass().getName(), "run");
+ ui.showWelcome();
+ try {
+ data.load();
+ } catch (AthletiException e) {
+ ui.showException(e);
+ data.clear();
+ }
+ boolean isExit = false;
+ boolean isShutdownHookAdded = false;
+ while (!isExit) {
+ final String rawUserInput = ui.getUserCommand();
+ try {
+ logger.info("Command read: " + rawUserInput);
+ final Command command = Parser.parseCommand(rawUserInput);
+ final String[] feedback = command.execute(data);
+ ui.showMessages(feedback);
+ logger.info("Command executed successfully");
+ isExit = command.isExit();
+ /* add shutdown hook if the first valid command is not exit */
+ if (!isExit && !isShutdownHookAdded) {
+ /* save data when the JVM begins its shutdown sequence */
+ Runtime.getRuntime().addShutdownHook(runSaveCommand);
+ isShutdownHookAdded = true;
+ }
+ } catch (AthletiException e) {
+ ui.showException(e);
+ logger.warning("Exception caught: " + e);
+ }
+ }
+ logger.exiting(getClass().getName(), "run");
+ }
+}
diff --git a/src/main/java/athleticli/commands/ByeCommand.java b/src/main/java/athleticli/commands/ByeCommand.java
new file mode 100644
index 0000000000..afb77333d5
--- /dev/null
+++ b/src/main/java/athleticli/commands/ByeCommand.java
@@ -0,0 +1,26 @@
+package athleticli.commands;
+
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+public class ByeCommand extends Command {
+ /**
+ * Returns true if this is a ByeCommand object, otherwise returns false.
+ *
+ * @return true if this is a ByeCommand object, otherwise returns false.
+ */
+ @Override
+ public boolean isExit() {
+ return true;
+ }
+
+ /**
+ * Returns the bye message to be shown to the user.
+ *
+ * @return The messages to be shown to the user.
+ */
+ public String[] execute(Data data) throws AthletiException {
+ return new String[] {Message.MESSAGE_BYE};
+ }
+}
diff --git a/src/main/java/athleticli/commands/Command.java b/src/main/java/athleticli/commands/Command.java
new file mode 100644
index 0000000000..3015f2d6b4
--- /dev/null
+++ b/src/main/java/athleticli/commands/Command.java
@@ -0,0 +1,27 @@
+package athleticli.commands;
+
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+
+/**
+ * Defines the basic methods of a command.
+ */
+public abstract class Command {
+ /**
+ * Executes the command and returns the messages to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException
+ */
+ public abstract String[] execute(Data data) throws AthletiException;
+
+ /**
+ * Returns true if this is a ByeCommand object, otherwise returns false.
+ *
+ * @return true if this is a ByeCommand object, otherwise returns false.
+ */
+ public boolean isExit() {
+ return false;
+ }
+}
diff --git a/src/main/java/athleticli/commands/FindCommand.java b/src/main/java/athleticli/commands/FindCommand.java
new file mode 100644
index 0000000000..05291bdc28
--- /dev/null
+++ b/src/main/java/athleticli/commands/FindCommand.java
@@ -0,0 +1,36 @@
+package athleticli.commands;
+
+import java.time.LocalDate;
+import java.util.stream.Stream;
+
+import athleticli.commands.activity.FindActivityCommand;
+import athleticli.commands.diet.FindDietCommand;
+import athleticli.commands.sleep.FindSleepCommand;
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+
+public class FindCommand extends Command {
+ protected LocalDate date;
+
+ public FindCommand(LocalDate date) {
+ this.date = date;
+ }
+
+ /**
+ * Returns the records to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The records to be shown to the user.
+ * @throws AthletiException
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ var activities = Stream.of(new FindActivityCommand(date).execute(data));
+ var diets = Stream.of(new FindDietCommand(date).execute(data));
+ var sleeps = Stream.of(new FindSleepCommand(date).execute(data));
+ return Stream.of(activities, diets, sleeps)
+ .reduce(Stream::concat)
+ .orElseGet(Stream::empty)
+ .toArray(String[]::new);
+ }
+}
diff --git a/src/main/java/athleticli/commands/HelpCommand.java b/src/main/java/athleticli/commands/HelpCommand.java
new file mode 100644
index 0000000000..556d04be5a
--- /dev/null
+++ b/src/main/java/athleticli/commands/HelpCommand.java
@@ -0,0 +1,125 @@
+package athleticli.commands;
+
+import static java.util.Map.entry;
+
+import java.util.Map;
+
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+import athleticli.parser.CommandName;
+import athleticli.ui.Message;
+
+public class HelpCommand extends Command {
+ private static final String[] HELP_ALL = {
+ /* Activity Management */
+ "\nActivity Management:",
+ Message.HELP_ADD_ACTIVITY,
+ Message.HELP_ADD_RUN,
+ Message.HELP_ADD_SWIM,
+ Message.HELP_ADD_CYCLE,
+ Message.HELP_DELETE_ACTIVITY,
+ Message.HELP_LIST_ACTIVITY,
+ Message.HELP_EDIT_ACTIVITY,
+ Message.HELP_EDIT_RUN,
+ Message.HELP_EDIT_SWIM,
+ Message.HELP_EDIT_CYCLE,
+ Message.HELP_FIND_ACTIVITY,
+ Message.HELP_SET_ACTIVITY_GOAL,
+ Message.HELP_EDIT_ACTIVITY_GOAL,
+ Message.HELP_DELETE_ACTIVITY_GOAL,
+ Message.HELP_LIST_ACTIVITY_GOAL,
+ /* Diet Management */
+ "\nDiet Management:",
+ Message.HELP_ADD_DIET,
+ Message.HELP_EDIT_DIET,
+ Message.HELP_DELETE_DIET,
+ Message.HELP_LIST_DIET,
+ Message.HELP_FIND_DIET,
+
+ Message.HELP_SET_DIET_GOAL,
+ Message.HELP_EDIT_DIET_GOAL,
+ Message.HELP_DELETE_DIET_GOAL,
+ Message.HELP_LIST_DIET_GOAL,
+ /* Sleep Management */
+ "\nSleep Management:",
+ Message.HELP_ADD_SLEEP,
+ Message.HELP_LIST_SLEEP,
+ Message.HELP_DELETE_SLEEP,
+ Message.HELP_EDIT_SLEEP,
+ Message.HELP_FIND_SLEEP,
+ Message.HELP_SET_SLEEP_GOAL,
+ Message.HELP_EDIT_SLEEP_GOAL,
+ Message.HELP_LIST_SLEEP_GOAL,
+ /* Misc */
+ "\nMisc:",
+ Message.HELP_FIND,
+ Message.HELP_SAVE,
+ Message.HELP_BYE,
+ Message.HELP_HELP,
+ "\n" + Message.HELP_DETAILS
+ };
+ private static final Map HELP_MESSAGES = Map.ofEntries(
+ /* Activity Management */
+ entry(CommandName.COMMAND_ACTIVITY, Message.HELP_ADD_ACTIVITY),
+ entry(CommandName.COMMAND_RUN, Message.HELP_ADD_RUN),
+ entry(CommandName.COMMAND_SWIM, Message.HELP_ADD_SWIM),
+ entry(CommandName.COMMAND_CYCLE, Message.HELP_ADD_CYCLE),
+ entry(CommandName.COMMAND_ACTIVITY_DELETE, Message.HELP_DELETE_ACTIVITY),
+ entry(CommandName.COMMAND_ACTIVITY_LIST, Message.HELP_LIST_ACTIVITY),
+ entry(CommandName.COMMAND_ACTIVITY_EDIT, Message.HELP_EDIT_ACTIVITY),
+ entry(CommandName.COMMAND_RUN_EDIT, Message.HELP_EDIT_RUN),
+ entry(CommandName.COMMAND_SWIM_EDIT, Message.HELP_EDIT_SWIM),
+ entry(CommandName.COMMAND_CYCLE_EDIT, Message.HELP_EDIT_CYCLE),
+ entry(CommandName.COMMAND_ACTIVITY_FIND, Message.HELP_FIND_ACTIVITY),
+ entry(CommandName.COMMAND_ACTIVITY_GOAL_SET, Message.HELP_SET_ACTIVITY_GOAL),
+ entry(CommandName.COMMAND_ACTIVITY_GOAL_EDIT, Message.HELP_EDIT_ACTIVITY_GOAL),
+ entry(CommandName.COMMAND_ACTIVITY_GOAL_DELETE, Message.HELP_DELETE_ACTIVITY_GOAL),
+ entry(CommandName.COMMAND_ACTIVITY_GOAL_LIST, Message.HELP_LIST_ACTIVITY_GOAL),
+ /* Diet Management */
+ entry(CommandName.COMMAND_DIET_ADD, Message.HELP_ADD_DIET),
+ entry(CommandName.COMMAND_DIET_EDIT, Message.HELP_EDIT_DIET),
+ entry(CommandName.COMMAND_DIET_DELETE, Message.HELP_DELETE_DIET),
+ entry(CommandName.COMMAND_DIET_LIST, Message.HELP_LIST_DIET),
+ entry(CommandName.COMMAND_DIET_FIND, Message.HELP_FIND_DIET),
+
+ entry(CommandName.COMMAND_DIET_GOAL_SET, Message.HELP_SET_DIET_GOAL),
+ entry(CommandName.COMMAND_DIET_GOAL_EDIT, Message.HELP_EDIT_DIET_GOAL),
+ entry(CommandName.COMMAND_DIET_GOAL_DELETE, Message.HELP_DELETE_DIET_GOAL),
+ entry(CommandName.COMMAND_DIET_GOAL_LIST, Message.HELP_LIST_DIET_GOAL),
+ /* Sleep Management */
+ entry(CommandName.COMMAND_SLEEP_ADD, Message.HELP_ADD_SLEEP),
+ entry(CommandName.COMMAND_SLEEP_LIST, Message.HELP_LIST_SLEEP),
+ entry(CommandName.COMMAND_SLEEP_DELETE, Message.HELP_DELETE_SLEEP),
+ entry(CommandName.COMMAND_SLEEP_EDIT, Message.HELP_EDIT_SLEEP),
+ entry(CommandName.COMMAND_SLEEP_FIND, Message.HELP_FIND_SLEEP),
+ entry(CommandName.COMMAND_SLEEP_GOAL_SET, Message.HELP_SET_SLEEP_GOAL),
+ entry(CommandName.COMMAND_SLEEP_GOAL_EDIT, Message.HELP_EDIT_SLEEP_GOAL),
+ entry(CommandName.COMMAND_SLEEP_GOAL_LIST, Message.HELP_LIST_SLEEP_GOAL),
+ /* Misc */
+ entry(CommandName.COMMAND_FIND, Message.HELP_FIND),
+ entry(CommandName.COMMAND_SAVE, Message.HELP_SAVE),
+ entry(CommandName.COMMAND_BYE, Message.HELP_BYE),
+ entry(CommandName.COMMAND_HELP, Message.HELP_HELP)
+ );
+
+ private String command;
+ public HelpCommand(String command) {
+ this.command = command;
+ }
+
+ /**
+ * Returns the help messages to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ if (HELP_MESSAGES.containsKey(command)) {
+ return new String[] {"Usage: " + HELP_MESSAGES.get(command)};
+ } else {
+ return HELP_ALL;
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/SaveCommand.java b/src/main/java/athleticli/commands/SaveCommand.java
new file mode 100644
index 0000000000..1cdd363615
--- /dev/null
+++ b/src/main/java/athleticli/commands/SaveCommand.java
@@ -0,0 +1,27 @@
+package athleticli.commands;
+
+import java.io.IOException;
+
+import athleticli.data.Data;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+public class SaveCommand extends Command {
+ /**
+ * Saves the data into the file.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ assert data != null;
+ try {
+ data.save();
+ } catch (IOException e) {
+ throw new AthletiException(Message.MESSAGE_IO_EXCEPTION);
+ }
+ return new String[] {Message.MESSAGE_SAVE};
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/AddActivityCommand.java b/src/main/java/athleticli/commands/activity/AddActivityCommand.java
new file mode 100644
index 0000000000..987ea700ed
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/AddActivityCommand.java
@@ -0,0 +1,46 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.Activity;
+import athleticli.data.activity.ActivityList;
+import athleticli.ui.Message;
+
+/**
+ * Executes the add activity commands provided by the user.
+ */
+public class AddActivityCommand extends Command {
+ private final Activity activity;
+
+ /**
+ * Constructor for AddActivityCommand.
+ *
+ * @param activity Activity to be added.
+ */
+ public AddActivityCommand(Activity activity){
+ this.activity = activity;
+ }
+
+ /**
+ * Updates the activity list by adding a new activity, sorts the list and returns a message to the user.
+ *
+ * @param data Current data containing the activity list.
+ * @return An array of message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) {
+ ActivityList activities = data.getActivities();
+ activities.add(activity);
+ activities.sort();
+ int size = activities.size();
+
+ String countMessage;
+ if (size > 1) {
+ countMessage = String.format(Message.MESSAGE_ACTIVITY_COUNT, size);
+ } else {
+ countMessage = Message.MESSAGE_ACTIVITY_FIRST;
+ }
+
+ return new String[]{Message.MESSAGE_ACTIVITY_ADDED, activity.toString(), countMessage};
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/DeleteActivityCommand.java b/src/main/java/athleticli/commands/activity/DeleteActivityCommand.java
new file mode 100644
index 0000000000..a638cfb1b2
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/DeleteActivityCommand.java
@@ -0,0 +1,48 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.Activity;
+import athleticli.data.activity.ActivityList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Executes the delete activity command provided by the user.
+ */
+public class DeleteActivityCommand extends Command {
+ private final Integer index;
+
+ /**
+ * Constructs DeleteActivityCommand.
+ *
+ * @param index Index of activity to be deleted.
+ */
+ public DeleteActivityCommand(Integer index) {
+ this.index = index;
+ }
+
+ /**
+ * Deletes the activity at the specified index from the list of activities.
+ *
+ * @param data Data object containing the current list of activities.
+ * @return String array containing the messages to be printed to the user.
+ * @throws AthletiException If the index provided is out of bounds.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ ActivityList activities = data.getActivities();
+ try {
+ // Adjusting index as user input is 1-based and list is 0-based
+ final Activity activity = activities.get(index-1);
+ activities.remove(activity);
+ return new String[]{
+ Message.MESSAGE_ACTIVITY_DELETED,
+ activity.toString(),
+ String.format(Message.MESSAGE_ACTIVITY_COUNT, activities.size())
+ };
+ } catch (IndexOutOfBoundsException e) {
+ throw new AthletiException(Message.MESSAGE_ACTIVITY_INDEX_OUT_OF_BOUNDS);
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/DeleteActivityGoalCommand.java b/src/main/java/athleticli/commands/activity/DeleteActivityGoalCommand.java
new file mode 100644
index 0000000000..1adbd596a4
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/DeleteActivityGoalCommand.java
@@ -0,0 +1,66 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.Goal.TimeSpan;
+import athleticli.data.activity.ActivityGoal;
+import athleticli.data.activity.ActivityGoal.GoalType;
+import athleticli.data.activity.ActivityGoal.Sport;
+import athleticli.data.activity.ActivityGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Represents a command which deletes an activity goal.
+ */
+public class DeleteActivityGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(DeleteActivityGoalCommand.class.getName());
+ GoalType goalType;
+ Sport sport;
+ TimeSpan timeSpan;
+
+
+ /**
+ * Constructor for DeleteActivityGoalCommand.
+ *
+ * @param activityGoal Activity goal to be deleted.
+ */
+ public DeleteActivityGoalCommand(ActivityGoal activityGoal) {
+ this.goalType = activityGoal.getGoalType();
+ this.sport = activityGoal.getSport();
+ this.timeSpan = activityGoal.getTimeSpan();
+ }
+
+
+ /**
+ * Deletes the activity goal from the activity goal list.
+ *
+ * @param data The current data containing the activity goal list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException if no such goal exists
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ logger.info("Deleting activity goal with goal type " + this.goalType + " and sport " + this.sport +
+ " and time span " + this.timeSpan);
+ ActivityGoalList activityGoals = data.getActivityGoals();
+ String activityGoalString = "";
+ if (!activityGoals.isDuplicate(this.goalType, this.sport, this.timeSpan)) {
+ logger.warning("No such goal exists");
+ throw new AthletiException(Message.MESSAGE_NO_SUCH_GOAL_EXISTS);
+ }
+ for (int i = 0; i < activityGoals.size(); i++) {
+ if (activityGoals.get(i).getGoalType() == this.goalType &&
+ activityGoals.get(i).getSport() == this.sport &&
+ activityGoals.get(i).getTimeSpan() == this.timeSpan) {
+ activityGoalString = activityGoals.get(i).toString(data);
+ activityGoals.remove(i);
+ break;
+ }
+ }
+ logger.info("Activity goal deleted successfully");
+ return new String[]{Message.MESSAGE_ACTIVITY_GOAL_DELETED, activityGoalString};
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/EditActivityCommand.java b/src/main/java/athleticli/commands/activity/EditActivityCommand.java
new file mode 100644
index 0000000000..b39ea554f1
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/EditActivityCommand.java
@@ -0,0 +1,103 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.Activity;
+import athleticli.data.activity.ActivityChanges;
+import athleticli.data.activity.ActivityList;
+import athleticli.data.activity.Cycle;
+import athleticli.data.activity.Run;
+import athleticli.data.activity.Swim;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Executes the edit activity command provided by the user.
+ */
+public class EditActivityCommand extends Command {
+ private static final Logger logger = Logger.getLogger("EditActivityCommand");
+ private final int index;
+ private final ActivityChanges activityChanges;
+ private final Class> activityType;
+
+ /**
+ * Constructs EditActivityCommand.
+ *
+ * @param index Index of the activity to be edited.
+ * @param activityChanges Updated Activity.
+ */
+ public EditActivityCommand(int index, ActivityChanges activityChanges, Class> activityType) {
+ this.index = index;
+ assert index > 0 : "Index should be greater than 0";
+ this.activityChanges = activityChanges;
+ this.activityType = activityType;
+ }
+
+ /**
+ * Edits the activity at the specified index.
+ *
+ * @param data Data object containing the current list of activities.
+ * @return String array containing the messages to be printed to the user.
+ * @throws AthletiException If the index provided is out of bounds.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ logger.log(Level.INFO, "Editing activity at index " + index);
+ ActivityList activities = data.getActivities();
+ try {
+ // Adjusting index as user input is 1-based and list is 0-based
+ Activity activity = activities.get(index-1);
+
+ if (!activityType.isInstance(activity)) {
+ throw new AthletiException(Message.MESSAGE_ACTIVITY_TYPE_MISMATCH);
+ }
+
+ applyActivityChanges(activity, activityChanges);
+
+ activities.sort();
+ logger.log(java.util.logging.Level.INFO, "Activity at index " + index + "successfully edited");
+ return new String[]{
+ Message.MESSAGE_ACTIVITY_UPDATED,
+ activity.toString(),
+ String.format(Message.MESSAGE_ACTIVITY_COUNT, activities.size())
+ };
+ } catch (IndexOutOfBoundsException e) {
+ logger.log(Level.WARNING, "Activity index out of bounds");
+ throw new AthletiException(Message.MESSAGE_ACTIVITY_INDEX_OUT_OF_BOUNDS);
+ }
+ }
+
+ /**
+ * Applies the changes to the activity object.
+ *
+ * @param activity Activity to be edited.
+ * @param activityChanges ActivityChanges object containing the changes to be applied.
+ */
+ private void applyActivityChanges(Activity activity, ActivityChanges activityChanges) {
+ if (activityChanges.getCaption() != null) {
+ activity.setCaption(activityChanges.getCaption());
+ }
+ if (activityChanges.getDistance() != 0) {
+ activity.setDistance(activityChanges.getDistance());
+ }
+ if (activityChanges.getDuration() != null) {
+ activity.setMovingTime(activityChanges.getDuration());
+ }
+ if (activityChanges.getStartDateTime() != null) {
+ activity.setStartDateTime(activityChanges.getStartDateTime());
+ }
+ if (activityChanges.getElevation() != 0) {
+ if (activity instanceof Run) {
+ ((Run) activity).setElevationGain(activityChanges.getElevation());
+ } else if (activity instanceof Cycle) {
+ ((Cycle) activity).setElevationGain(activityChanges.getElevation());
+ }
+ }
+ if (activity instanceof Swim && activityChanges.getSwimmingStyle() != null) {
+ ((Swim) activity).setStyle(activityChanges.getSwimmingStyle());
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/EditActivityGoalCommand.java b/src/main/java/athleticli/commands/activity/EditActivityGoalCommand.java
new file mode 100644
index 0000000000..9b4c9eab59
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/EditActivityGoalCommand.java
@@ -0,0 +1,53 @@
+package athleticli.commands.activity;
+
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.ActivityGoal;
+import athleticli.data.activity.ActivityGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Represents a command which edits an activity goal.
+ */
+public class EditActivityGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(EditActivityGoalCommand.class.getName());
+ private final ActivityGoal activityGoal;
+
+ /**
+ * Constructor for EditActivityGoalCommand.
+ *
+ * @param activityGoal Activity goal to be edited.
+ */
+ public EditActivityGoalCommand(ActivityGoal activityGoal) {
+ this.activityGoal = activityGoal;
+ }
+
+ /**
+ * Updates the activity goal list.
+ *
+ * @param data The current data containing the activity goal list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException if no such goal exists
+ */
+ @Override
+ public String[] execute(Data data) throws athleticli.exceptions.AthletiException {
+ logger.info("Editing activity goal with goal type " + this.activityGoal.getGoalType() + " and sport " +
+ this.activityGoal.getSport() + " and time span " + this.activityGoal.getTimeSpan());
+ ActivityGoalList activityGoals = data.getActivityGoals();
+ for (ActivityGoal goal : activityGoals) {
+ if (goal.getSport() == this.activityGoal.getSport() &&
+ goal.getGoalType() == this.activityGoal.getGoalType() &&
+ goal.getTimeSpan() == this.activityGoal.getTimeSpan()) {
+ goal.setTargetValue(this.activityGoal.getTargetValue());
+ logger.info("Activity goal edited successfully");
+ return new String[]{Message.MESSAGE_ACTIVITY_GOAL_EDITED, this.activityGoal.toString(data)};
+ }
+ }
+ logger.warning("No such goal exists");
+ throw new AthletiException(Message.MESSAGE_NO_SUCH_GOAL_EXISTS);
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/FindActivityCommand.java b/src/main/java/athleticli/commands/activity/FindActivityCommand.java
new file mode 100644
index 0000000000..29a70dcaf3
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/FindActivityCommand.java
@@ -0,0 +1,35 @@
+package athleticli.commands.activity;
+
+import java.time.LocalDate;
+import java.util.stream.Stream;
+
+import athleticli.commands.FindCommand;
+import athleticli.data.Data;
+import athleticli.data.activity.Activity;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+public class FindActivityCommand extends FindCommand {
+ public FindActivityCommand(LocalDate date) {
+ super(date);
+ }
+
+ /**
+ * Returns the activities matching the date to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ var resultStream = data.getActivities()
+ .find(date)
+ .stream()
+ .filter(Activity.class::isInstance)
+ .map(Activity.class::cast)
+ .map(Activity::toString);
+ return Stream.concat(Stream.of(Message.MESSAGE_ACTIVITY_FIND), resultStream)
+ .toArray(String[]::new);
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/ListActivityCommand.java b/src/main/java/athleticli/commands/activity/ListActivityCommand.java
new file mode 100644
index 0000000000..b1f94b0512
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/ListActivityCommand.java
@@ -0,0 +1,83 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.Activity;
+import athleticli.data.activity.ActivityList;
+import athleticli.ui.Message;
+
+/**
+ * Executes the list activity command provided by the user.
+ */
+public class ListActivityCommand extends Command {
+ private final boolean isDetailed;
+
+ /**
+ * Constructs instance of ListActivityCommand.
+ *
+ * @param isDetailed Whether the list should be detailed.
+ */
+ public ListActivityCommand(boolean isDetailed) {
+ this.isDetailed = isDetailed;
+ }
+
+ /**
+ * Lists the activities in either a detailed or summary format.
+ *
+ * @param data Current data containing the activity list.
+ * @return The message containing listing of activities which will be shown to the user. The format is
+ * based on the 'isDetailed' flag.
+ */
+ @Override
+ public String[] execute(Data data) {
+ ActivityList activities = data.getActivities();
+ final int size = activities.size();
+
+ if (size == 0) {
+ return new String[]{Message.MESSAGE_EMPTY_ACTIVITY_LIST};
+ }
+
+ if (isDetailed) {
+ return printDetailedList(activities, size);
+ } else {
+ return printList(activities, size);
+ }
+ }
+
+ /**
+ * Prints the list of activities.
+ *
+ * @param activities The current activity list.
+ * @param size The size of the activity list.
+ * @return The message containing listing of activities which will be shown to the user.
+ */
+ public String[] printList(ActivityList activities, int size) {
+ String[] output = new String[size + 2];
+ output[0] = Message.MESSAGE_ACTIVITY_LIST;
+
+ int index = 1;
+ for (Activity activity : activities) {
+ output[index++] = index-1 + "." + activity.toString();
+ }
+
+ output[index] = Message.MESSAGE_ACTIVITY_LIST_END;
+ return output;
+ }
+
+ /**
+ * Prints the detailed list of activities.
+ *
+ * @param activities The current activity list.
+ * @param size The size of the activity list.
+ * @return The message containing listing of activities which will be shown to the user.
+ */
+ public String[] printDetailedList(ActivityList activities, int size) {
+ String[] output = new String[size + 1];
+ output[0] = Message.MESSAGE_ACTIVITY_LIST;
+ int index = 1;
+ for (Activity activity : activities) {
+ output[index++] = activity.toDetailedString();
+ }
+ return output;
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/ListActivityGoalCommand.java b/src/main/java/athleticli/commands/activity/ListActivityGoalCommand.java
new file mode 100644
index 0000000000..a321e39967
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/ListActivityGoalCommand.java
@@ -0,0 +1,40 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.ActivityGoalList;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Lists the activity goals.
+ */
+public class ListActivityGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(ListActivityGoalCommand.class.getName());
+ /**
+ * Constructor for ListActivityCommand.
+ */
+ public ListActivityGoalCommand() {
+ }
+
+ /**
+ * Lists the activities.
+ *
+ * @param data The current data containing the activity list.
+ * @return The message containing listing of activities which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) {
+ logger.info("Listing activity goals");
+ ActivityGoalList activityGoals = data.getActivityGoals();
+ int size = activityGoals.size();
+ String[] output = new String[size + 1];
+ output[0] = Message.MESSAGE_ACTIVITY_GOAL_LIST;
+ for (int i = 0; i < activityGoals.size(); i++) {
+ output[i + 1] = (i + 1) + ". " + activityGoals.get(i).toString(data);
+ }
+ logger.info("Found " + size + " activity goals");
+ return output;
+ }
+}
diff --git a/src/main/java/athleticli/commands/activity/SetActivityGoalCommand.java b/src/main/java/athleticli/commands/activity/SetActivityGoalCommand.java
new file mode 100644
index 0000000000..43e0c936f8
--- /dev/null
+++ b/src/main/java/athleticli/commands/activity/SetActivityGoalCommand.java
@@ -0,0 +1,44 @@
+package athleticli.commands.activity;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.activity.ActivityGoal;
+import athleticli.data.activity.ActivityGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which adds an activity goal to the activity goal list.
+ */
+public class SetActivityGoalCommand extends Command {
+ private final ActivityGoal activityGoal;
+
+ /**
+ * Constructs instance of SetActivityGoalCommand.
+ *
+ * @param activityGoal Activity goal to be added.
+ */
+ public SetActivityGoalCommand(ActivityGoal activityGoal){
+ this.activityGoal = activityGoal;
+ }
+
+ /**
+ * Adds the activity goal to the activity goal list.
+ *
+ * @param data The current data containing the activity goal list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException If a duplicate activity goal is detected.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ ActivityGoalList activityGoals = data.getActivityGoals();
+
+ if (activityGoals.isDuplicate(activityGoal.getGoalType(), activityGoal.getSport(),
+ activityGoal.getTimeSpan())) {
+ throw new AthletiException(Message.MESSAGE_DUPLICATE_ACTIVITY_GOAL);
+ }
+
+ activityGoals.add(this.activityGoal);
+ return new String[]{Message.MESSAGE_ACTIVITY_GOAL_ADDED, this.activityGoal.toString(data)};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/AddDietCommand.java b/src/main/java/athleticli/commands/diet/AddDietCommand.java
new file mode 100644
index 0000000000..a34604e3e8
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/AddDietCommand.java
@@ -0,0 +1,49 @@
+package athleticli.commands.diet;
+
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.Diet;
+import athleticli.data.diet.DietList;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Executes the add diet commands provided by the user.
+ */
+public class AddDietCommand extends Command {
+ private static final Logger logger = Logger.getLogger(AddDietCommand.class.getName());
+ private final Diet diet;
+
+ /**
+ * Constructor for AddDietCommand.
+ *
+ * @param diet Diet to be added.
+ */
+ public AddDietCommand(Diet diet) {
+ this.diet = diet;
+ }
+
+ /**
+ * Updates the diet list.
+ *
+ * @param data The current data containing the diet list.
+ * @return The message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) {
+ logger.info("Adding diet" + diet.toString());
+ DietList diets = data.getDiets();
+ diets.add(this.diet);
+ int size = diets.size();
+ String countMessage;
+ if (size > 1) {
+ countMessage = String.format(Message.MESSAGE_DIET_COUNT, size);
+ } else {
+ countMessage = Message.MESSAGE_DIET_FIRST;
+ }
+ logger.info("Diet added successfully");
+ return new String[]{Message.MESSAGE_DIET_ADDED, this.diet.toString(), countMessage};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/DeleteDietCommand.java b/src/main/java/athleticli/commands/diet/DeleteDietCommand.java
new file mode 100644
index 0000000000..571bb711ae
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/DeleteDietCommand.java
@@ -0,0 +1,49 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.Diet;
+import athleticli.data.diet.DietList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Executes the add diet commands provided by the user.
+ */
+public class DeleteDietCommand extends Command {
+ private static final Logger logger = Logger.getLogger(DeleteDietCommand.class.getName());
+ private final int index;
+
+ /**
+ * Constructor for AddDietCommand.
+ *
+ * @param index Diet to be added.
+ */
+ public DeleteDietCommand(int index) {
+ assert index > 0 : "Index cannot be less than 1";
+ this.index = index;
+ }
+
+ /**
+ * Updates the diet list.
+ *
+ * @param data The current data containing the diet list.
+ * @return The message which will be shown to the user.
+ */
+ public String[] execute(Data data) throws AthletiException {
+ logger.info("Deleting diet at index " + index);
+ DietList dietList = data.getDiets();
+ int size = dietList.size();
+ if (index > size) {
+ logger.warning("Index out of bounds");
+ throw new AthletiException(Message.MESSAGE_INVALID_DIET_INDEX);
+ }
+ Diet oldDiet = dietList.get(index - 1);
+ dietList.remove(index - 1);
+ logger.info("Diet deleted successfully");
+ return new String[]{Message.MESSAGE_DIET_DELETED, oldDiet.toString(),
+ String.format(Message.MESSAGE_DIET_COUNT, size - 1)};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/DeleteDietGoalCommand.java b/src/main/java/athleticli/commands/diet/DeleteDietGoalCommand.java
new file mode 100644
index 0000000000..62391b6309
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/DeleteDietGoalCommand.java
@@ -0,0 +1,65 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.DietGoal;
+import athleticli.data.diet.DietGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.io.IOException;
+
+import java.util.logging.ConsoleHandler;
+import java.util.logging.FileHandler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * Executes the delete-diet-goal commands provided by the user.
+ */
+public class DeleteDietGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(DeleteDietGoalCommand.class.getName());
+ private final int deleteIndex;
+
+ /**
+ * This is a constructor to set up the delete diet goal command.
+ *
+ * @param deleteIndex Index of the diet goal to be deleted in the users' perspective.
+ */
+ public DeleteDietGoalCommand(int deleteIndex) {
+ //deleteIndex that is less than or equal to zero would result in exception
+ assert deleteIndex >= 1: "'deleteIndex' should have the value of 1 minimally.";
+ this.deleteIndex = deleteIndex;
+ LogManager.getLogManager().reset();
+ try {
+ logger.addHandler(new FileHandler("%t/athleticli-log.txt"));
+ } catch(IOException e) {
+ logger.addHandler(new ConsoleHandler());
+ }
+ }
+
+ /**
+ * Deletes a goal from the Diet Goal List.
+ *
+ * @param data The current data containing the different nutrient goals.
+ * @return The message which will be shown to the user.
+ */
+ public String[] execute(Data data) throws AthletiException {
+ logger.log(Level.FINE, "Executing delete command for diet goals");
+ DietGoalList dietGoals = data.getDietGoals();
+ if (dietGoals.isEmpty()) {
+ throw new AthletiException(Message.MESSAGE_DIET_GOAL_EMPTY_DIET_GOAL_LIST);
+ }
+ try {
+ DietGoal dietGoalRemoved = dietGoals.get(deleteIndex - 1);
+ dietGoals.remove(deleteIndex - 1);
+ logger.log(Level.FINE, String.format("Diet goals %s has been successfully removed",
+ dietGoalRemoved.getNutrient()));
+ return new String[]{Message.MESSAGE_DIET_GOAL_DELETE_HEADER,
+ dietGoalRemoved.toString(data)};
+ } catch (IndexOutOfBoundsException e) {
+ throw new AthletiException(String.format(Message.MESSAGE_DIET_GOAL_OUT_OF_BOUND, dietGoals.size()));
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/EditDietCommand.java b/src/main/java/athleticli/commands/diet/EditDietCommand.java
new file mode 100644
index 0000000000..a7e98d4b1a
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/EditDietCommand.java
@@ -0,0 +1,81 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.Diet;
+import athleticli.data.diet.DietList;
+import athleticli.exceptions.AthletiException;
+import athleticli.parser.Parameter;
+import athleticli.parser.Parser;
+import athleticli.ui.Message;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+/**
+ * Executes the edit diet command provided by the user.
+ */
+public class EditDietCommand extends Command {
+ private static final Logger logger = Logger.getLogger(EditDietCommand.class.getName());
+ private final int index;
+ private final HashMap dietMap;
+
+ /**
+ * Constructor for EditDietCommand.
+ *
+ * @param index Index of the diet to be edited.
+ * @param dietMap Updated Diet.
+ */
+ public EditDietCommand(int index, HashMap dietMap) {
+ assert index > 0 : "Index should be greater than 0";
+ assert !dietMap.isEmpty() : "Diet map should not be empty";
+ this.index = index;
+ this.dietMap = dietMap;
+ }
+
+ /**
+ * Executes the edit diet command.
+ *
+ * @param data Data object containing the current list of diets.
+ * @return String array containing the messages to be printed to the user.
+ * @throws AthletiException If the index provided is out of bounds.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ logger.info("Editing diet at index " + index);
+ DietList diets = data.getDiets();
+ int size = diets.size();
+ if (index > size) {
+ logger.warning("Index out of bounds");
+ throw new AthletiException(Message.MESSAGE_INVALID_DIET_INDEX);
+ }
+ Diet oldDiet = diets.get(index - 1);
+ for (String key : dietMap.keySet()) {
+ assert !java.util.Objects.equals(dietMap.get(key), "") : "Diet parameter should not be empty";
+ switch (key) {
+ case Parameter.CALORIES_SEPARATOR:
+ oldDiet.setCalories(Integer.parseInt(dietMap.get(key)));
+ break;
+ case Parameter.PROTEIN_SEPARATOR:
+ oldDiet.setProtein(Integer.parseInt(dietMap.get(key)));
+ break;
+ case Parameter.CARB_SEPARATOR:
+ oldDiet.setCarb(Integer.parseInt(dietMap.get(key)));
+ break;
+ case Parameter.FAT_SEPARATOR:
+ oldDiet.setFat(Integer.parseInt(dietMap.get(key)));
+ break;
+ case Parameter.DATETIME_SEPARATOR:
+ LocalDateTime dateTime = Parser.parseDateTime(dietMap.get(key));
+ oldDiet.setDateTime(dateTime);
+ break;
+ default:
+ break;
+ }
+ }
+ diets.set(index - 1, oldDiet);
+ logger.info("Diet edited successfully");
+ return new String[]{Message.MESSAGE_DIET_UPDATED, oldDiet.toString()};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/EditDietGoalCommand.java b/src/main/java/athleticli/commands/diet/EditDietGoalCommand.java
new file mode 100644
index 0000000000..1c4a580cb3
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/EditDietGoalCommand.java
@@ -0,0 +1,94 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+
+import athleticli.data.diet.DietGoal;
+import athleticli.data.diet.DietGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.ArrayList;
+
+/**
+ * Executes the edit-diet-goal commands provided by the user.
+ */
+public class EditDietGoalCommand extends Command {
+ private final ArrayList userUpdatedDietGoals;
+
+ /**
+ * This is a constructor to set up the edit diet goal command.
+ *
+ * @param dietGoals This is a list consisting of updated existing diet goals.
+ * to be added to the current goal list.
+ */
+ public EditDietGoalCommand(ArrayList dietGoals) {
+ userUpdatedDietGoals = dietGoals;
+ }
+
+ /**
+ * Updates the Diet Goal List.
+ *
+ * @param data The current data containing the different nutrient goals.
+ * @return The message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ DietGoalList currentDietGoals = data.getDietGoals();
+ verifyEditedGoalsValid(currentDietGoals);
+ updateUserGoals(currentDietGoals);
+ return generateEditDietGoalSuccessMessage(data, currentDietGoals);
+ }
+
+ private static String[] generateEditDietGoalSuccessMessage(Data data, DietGoalList currentDietGoals) {
+ int dietGoalNum = currentDietGoals.size();
+ return new String[]{Message.MESSAGE_DIET_GOAL_LIST_HEADER, currentDietGoals.toString(data),
+ String.format(Message.MESSAGE_DIET_GOAL_COUNT, dietGoalNum)};
+ }
+
+ private void updateUserGoals(DietGoalList currentDietGoals) {
+ int newTargetValue;
+ for (DietGoal userUpdatedDietGoal : userUpdatedDietGoals) {
+ for (DietGoal currentDietGoal : currentDietGoals) {
+ boolean isSameDietGoalNutrient =
+ userUpdatedDietGoal.getNutrient().equals(currentDietGoal.getNutrient());
+ boolean isSameTimeSpan = userUpdatedDietGoal.getTimeSpan().getDays()
+ == currentDietGoal.getTimeSpan().getDays();
+ if (!isSameDietGoalNutrient) {
+ continue;
+ }
+ if (!isSameTimeSpan) {
+ continue;
+ }
+ //update new target value to the current goal
+ newTargetValue = userUpdatedDietGoal.getTargetValue();
+ currentDietGoal.setTargetValue(newTargetValue);
+ }
+ }
+ }
+
+ private void verifyEditedGoalsValid(DietGoalList currentDietGoals) throws AthletiException {
+ for (DietGoal userDietGoal : userUpdatedDietGoals) {
+ boolean isDietGoalExisted = false;
+ currentDietGoals.isDietGoalTypeValid(userDietGoal);
+
+ if (currentDietGoals.isDietGoalUnique(userDietGoal)) {
+ throw new AthletiException(String.format(Message.MESSAGE_DIET_GOAL_NOT_EXISTED,
+ userDietGoal.getNutrient(), userDietGoal.getTimeSpan().toString()));
+ }
+ if (!currentDietGoals.isDietGoalTypeValid(userDietGoal)) {
+ throw new AthletiException(Message.MESSAGE_DIET_GOAL_TYPE_CLASH);
+ }
+ if (!currentDietGoals.isTargetValueConsistentWithTimeSpan(userDietGoal)) {
+ throw new AthletiException(Message.MESSAGE_DIET_GOAL_TARGET_VALUE_NOT_SCALING_WITH_TIME_SPAN);
+ }
+ isDietGoalExisted = true;
+
+ if (!isDietGoalExisted) {
+ throw new AthletiException(String.format(Message.MESSAGE_DIET_GOAL_NOT_EXISTED,
+ userDietGoal.getNutrient(), userDietGoal.getTimeSpan().toString()));
+ }
+ }
+ }
+}
+
diff --git a/src/main/java/athleticli/commands/diet/FindDietCommand.java b/src/main/java/athleticli/commands/diet/FindDietCommand.java
new file mode 100644
index 0000000000..2bb21b8f41
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/FindDietCommand.java
@@ -0,0 +1,43 @@
+package athleticli.commands.diet;
+
+import java.time.LocalDate;
+import java.util.stream.Stream;
+
+import athleticli.commands.FindCommand;
+import athleticli.data.Data;
+import athleticli.data.diet.Diet;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+
+/**
+ * Finds diets matching the date.
+ */
+public class FindDietCommand extends FindCommand {
+ private static final Logger logger = Logger.getLogger(FindDietCommand.class.getName());
+ public FindDietCommand(LocalDate date) {
+ super(date);
+ }
+
+ /**
+ * Returns the diets matching the date to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ logger.info("Finding diets on " + date);
+ var resultStream = data.getDiets()
+ .find(date)
+ .stream()
+ .filter(Diet.class::isInstance)
+ .map(Diet.class::cast)
+ .map(Diet::toString);
+ return Stream.concat(Stream.of(Message.MESSAGE_DIET_FIND), resultStream)
+ .toArray(String[]::new);
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/ListDietCommand.java b/src/main/java/athleticli/commands/diet/ListDietCommand.java
new file mode 100644
index 0000000000..01fd589119
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/ListDietCommand.java
@@ -0,0 +1,36 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.DietList;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Executes the list diet commands provided by the user.
+ */
+public class ListDietCommand extends Command {
+ private static final Logger logger = Logger.getLogger(ListDietCommand.class.getName());
+
+ /**
+ * Constructor for ListDietCommand.
+ */
+ public ListDietCommand() {
+ }
+
+ /**
+ * Updates the diet list.
+ *
+ * @param data The current data containing the diet list.
+ * @return The message which will be shown to the user.
+ */
+ public String[] execute(Data data) {
+ logger.info("Listing diets");
+ DietList dietList = data.getDiets();
+ int size = dietList.size();
+ logger.info("Found " + size + " diets");
+ return new String[]{Message.MESSAGE_DIET_LIST, dietList.toString(),
+ String.format(Message.MESSAGE_DIET_COUNT, size)};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/ListDietGoalCommand.java b/src/main/java/athleticli/commands/diet/ListDietGoalCommand.java
new file mode 100644
index 0000000000..877d6062d2
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/ListDietGoalCommand.java
@@ -0,0 +1,34 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.DietGoalList;
+import athleticli.ui.Message;
+
+/**
+ * Executes the list diet goal commands provided by the user.
+ */
+public class ListDietGoalCommand extends Command {
+
+ /**
+ * Constructor for ListDietGoalCommand.
+ */
+ public ListDietGoalCommand() {
+ }
+
+ /**
+ * Iterate and returns the string representation for each goal.
+ *
+ * @param data The current data containing the diet goal list.
+ * @return The message which will be shown to the user.
+ */
+ public String[] execute(Data data) {
+ DietGoalList dietGoalList = data.getDietGoals();
+ int dietGoalNum = dietGoalList.size();
+ if (dietGoalNum == 0) {
+ return new String[]{Message.MESSAGE_DIET_GOAL_NONE};
+ }
+ return new String[]{Message.MESSAGE_DIET_GOAL_LIST_HEADER, dietGoalList.toString(data),
+ String.format(Message.MESSAGE_DIET_GOAL_COUNT, dietGoalNum)};
+ }
+}
diff --git a/src/main/java/athleticli/commands/diet/SetDietGoalCommand.java b/src/main/java/athleticli/commands/diet/SetDietGoalCommand.java
new file mode 100644
index 0000000000..f383dc435f
--- /dev/null
+++ b/src/main/java/athleticli/commands/diet/SetDietGoalCommand.java
@@ -0,0 +1,66 @@
+package athleticli.commands.diet;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.diet.DietGoal;
+import athleticli.data.diet.DietGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.ArrayList;
+
+/**
+ * Executes the set-diet-goal commands provided by the user.
+ */
+public class SetDietGoalCommand extends Command {
+
+ private final ArrayList userNewDietGoals;
+
+ /**
+ * This is a constructor to set up the set diet goal command
+ *
+ * @param dietGoals This is a list consisting of new diet goals
+ * to be added to the current goal list.
+ */
+ public SetDietGoalCommand(ArrayList dietGoals) {
+ userNewDietGoals = dietGoals;
+ }
+
+ /**
+ * Updates the Diet Goal list.
+ *
+ * @param data The current data containing the different nutrients goal value.
+ * @return The message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ DietGoalList currentDietGoals = data.getDietGoals();
+ verifyNewGoalsValid(currentDietGoals);
+ addNewUserDietGoals(currentDietGoals);
+ return generateSetDietGoalSuccessMessage(data, currentDietGoals);
+ }
+
+ private static String[] generateSetDietGoalSuccessMessage(Data data, DietGoalList currentDietGoals) {
+ int dietGoalNum = currentDietGoals.size();
+ return new String[]{Message.MESSAGE_DIET_GOAL_LIST_HEADER, currentDietGoals.toString(data),
+ String.format(Message.MESSAGE_DIET_GOAL_COUNT, dietGoalNum)};
+ }
+
+ private void addNewUserDietGoals(DietGoalList currentDietGoals) {
+ currentDietGoals.addAll(userNewDietGoals);
+ }
+
+ private void verifyNewGoalsValid(DietGoalList currentDietGoals) throws AthletiException {
+ for (DietGoal userDietGoal : userNewDietGoals) {
+ if (!currentDietGoals.isDietGoalUnique(userDietGoal)) {
+ throw new AthletiException(String.format(Message.MESSAGE_DIET_GOAL_ALREADY_EXISTED,
+ userDietGoal.getNutrient()));
+ } else if (!currentDietGoals.isDietGoalTypeValid(userDietGoal)) {
+ throw new AthletiException(Message.MESSAGE_DIET_GOAL_TYPE_CLASH);
+ } else if (!currentDietGoals.isTargetValueConsistentWithTimeSpan(userDietGoal)) {
+ throw new AthletiException(Message.MESSAGE_DIET_GOAL_TARGET_VALUE_NOT_SCALING_WITH_TIME_SPAN);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/athleticli/commands/sleep/AddSleepCommand.java b/src/main/java/athleticli/commands/sleep/AddSleepCommand.java
new file mode 100644
index 0000000000..ae8aeab7b9
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/AddSleepCommand.java
@@ -0,0 +1,64 @@
+package athleticli.commands.sleep;
+
+import java.util.logging.Logger;
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.Sleep;
+import athleticli.data.sleep.SleepList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which adds a sleep entry.
+ */
+public class AddSleepCommand extends Command {
+ private final Logger logger = Logger.getLogger(AddSleepCommand.class.getName());
+ private final Sleep sleep;
+
+ /**
+ * Constructor for AddSleepCommand.
+ *
+ * @param sleep Sleep to be added.
+ */
+ public AddSleepCommand(Sleep sleep) {
+ this.sleep = sleep;
+ logger.fine("Creating AddSleepCommand with sleep: " + sleep.toString());
+ assert sleep.getStartDateTime() != null : "Start time cannot be null";
+ assert sleep.getEndDateTime() != null : "End time cannot be null";
+ assert sleep.getStartDateTime().isBefore(sleep.getEndDateTime()) : "Start time must be before end time";
+ }
+
+ /**
+ * Adds the sleep record to the sleep list. Sorts the sleep list after adding.
+ *
+ * @param data The current data containing the sleep list.
+ * @return The message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ SleepList sleeps = data.getSleeps();
+
+ for (Sleep s : sleeps) {
+ if (sleep.getStartDateTime().isBefore(s.getEndDateTime())
+ && sleep.getEndDateTime().isAfter(s.getStartDateTime())) {
+ throw new AthletiException(Message.ERRORMESSAGE_SLEEP_OVERLAP);
+ }
+ }
+
+ sleeps.add(this.sleep);
+ sleeps.sort();
+ int size = sleeps.size();
+
+ logger.info("Added sleep: " + this.sleep.toString());
+ logger.info("Sleep count: " + sleeps.size());
+ logger.info("Sleep list: " + sleeps.toString());
+
+ String countMessage;
+ if (size > 1) {
+ countMessage = String.format(Message.MESSAGE_SLEEP_COUNT, size);
+ } else {
+ countMessage = String.format(Message.MESSAGE_SLEEP_FIRST, size);
+ }
+ return new String[] {Message.MESSAGE_SLEEP_ADDED, this.sleep.toString(), countMessage};
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/DeleteSleepCommand.java b/src/main/java/athleticli/commands/sleep/DeleteSleepCommand.java
new file mode 100644
index 0000000000..d20ba377d7
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/DeleteSleepCommand.java
@@ -0,0 +1,55 @@
+package athleticli.commands.sleep;
+
+import java.util.logging.Logger;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.Sleep;
+import athleticli.data.sleep.SleepList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which deletes a sleep entry.
+ */
+public class DeleteSleepCommand extends Command {
+ private final Logger logger = Logger.getLogger(DeleteSleepCommand.class.getName());
+ private final int index;
+
+ /**
+ * Constructor for DeleteSleepCommand.
+ *
+ * @param index Index of the sleep to be deleted.
+ */
+ public DeleteSleepCommand(int index) {
+ this.index = index;
+ logger.fine("Creating DeleteSleepCommand with index: " + index);
+ }
+
+ /**
+ * Deletes the sleep record at the specified index.
+ *
+ * @param data The current data containing the sleep list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException If the index is out of bounds.
+ */
+ public String[] execute(Data data) throws AthletiException {
+ SleepList sleeps = data.getSleeps();
+ try {
+ final Sleep sleep = sleeps.get(index-1);
+ sleeps.remove(sleep);
+
+ logger.info("Deleting sleep: " + sleep.toString());
+ logger.info("Sleep count: " + sleeps.size());
+ logger.info("Sleep list: " + sleeps.toString());
+
+ return new String[]{
+ Message.MESSAGE_SLEEP_DELETED,
+ sleep.toString(),
+ String.format(Message.MESSAGE_SLEEP_COUNT, sleeps.size())
+ };
+ } catch (IndexOutOfBoundsException e) {
+ throw new AthletiException(Message.ERRORMESSAGE_SLEEP_DELETE_INDEX_OOBE);
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/EditSleepCommand.java b/src/main/java/athleticli/commands/sleep/EditSleepCommand.java
new file mode 100644
index 0000000000..ec6f80bb8b
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/EditSleepCommand.java
@@ -0,0 +1,61 @@
+package athleticli.commands.sleep;
+
+import java.util.logging.Logger;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.Sleep;
+import athleticli.data.sleep.SleepList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which edits a sleep entry.
+ */
+public class EditSleepCommand extends Command {
+ private static final Logger logger = Logger.getLogger(EditSleepCommand.class.getName());
+ private final int index;
+ private final Sleep newSleep;
+
+ /**
+ * Constructor for EditSleepCommand.
+ *
+ * @param index Index of the sleep to be edited.
+ * @param newSleep New sleep record to update the old one.
+ */
+ public EditSleepCommand(int index, Sleep newSleep) {
+ this.index = index;
+ this.newSleep = newSleep;
+ logger.fine("Creating EditSleepCommand with index: " + index);
+ }
+
+ /**
+ * Edits the sleep record at the specified index.
+ *
+ * @param data The current data containing the sleep list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException If the index is out of bounds.
+ */
+ public String[] execute(Data data) throws AthletiException {
+ SleepList sleeps = data.getSleeps();
+ for (Sleep s : sleeps) {
+ if (newSleep.getStartDateTime().isBefore(s.getEndDateTime())
+ && newSleep.getEndDateTime().isAfter(s.getStartDateTime())) {
+ throw new AthletiException(Message.ERRORMESSAGE_SLEEP_OVERLAP);
+ }
+ }
+ try {
+ final Sleep oldSleep = sleeps.get(index-1);
+ sleeps.set(index-1, newSleep);
+
+ logger.info("Activity at index " + index + " successfully edited");
+
+ return new String[]{Message.MESSAGE_SLEEP_EDITED,
+ "original: " + oldSleep,
+ "new: " + newSleep
+ };
+ } catch (IndexOutOfBoundsException e) {
+ throw new AthletiException(Message.ERRORMESSAGE_SLEEP_EDIT_INDEX_OOBE);
+ }
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/EditSleepGoalCommand.java b/src/main/java/athleticli/commands/sleep/EditSleepGoalCommand.java
new file mode 100644
index 0000000000..5dcb046ef1
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/EditSleepGoalCommand.java
@@ -0,0 +1,54 @@
+package athleticli.commands.sleep;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.SleepGoal;
+import athleticli.data.sleep.SleepGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Represents a command which edits an activity goal.
+ */
+public class EditSleepGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(EditSleepGoalCommand.class.getName());
+ private final SleepGoal sleepGoal;
+
+ /**
+ * Constructor for EditActivityGoalCommand.
+ *
+ * @param sleepGoal Activity goal to be edited.
+ */
+ public EditSleepGoalCommand(SleepGoal sleepGoal) {
+ this.sleepGoal = sleepGoal;
+ }
+
+ /**
+ * Updates the sleep goal list.
+ *
+ * @param data The current data containing the sleep goal list.
+ * @return The message which will be shown to the user.
+ * @throws AthletiException if no such goal exists
+ */
+
+ public String[] execute(Data data) throws athleticli.exceptions.AthletiException {
+ logger.info("Editing sleep goal with goal type " + this.sleepGoal.getGoalType() + " and time span " +
+ this.sleepGoal.getTimeSpan());
+
+ SleepGoalList sleepGoals = data.getSleepGoals();
+ for (SleepGoal goal : sleepGoals) {
+ if (goal.getGoalType() == this.sleepGoal.getGoalType() &&
+ goal.getTimeSpan() == this.sleepGoal.getTimeSpan()) {
+ goal.setTargetValue(this.sleepGoal.getTargetValue());
+ logger.info("Sleep goal edited successfully");
+ return new String[]{Message.MESSAGE_SLEEP_GOAL_EDITED, this.sleepGoal.toString(data)};
+ }
+ }
+
+ logger.warning("No such goal exists");
+
+ throw new AthletiException(Message.MESSAGE_NO_SUCH_GOAL_EXISTS);
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/FindSleepCommand.java b/src/main/java/athleticli/commands/sleep/FindSleepCommand.java
new file mode 100644
index 0000000000..d8b30c869a
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/FindSleepCommand.java
@@ -0,0 +1,47 @@
+package athleticli.commands.sleep;
+
+import java.time.LocalDate;
+import java.util.logging.Logger;
+import java.util.stream.Stream;
+
+import athleticli.commands.FindCommand;
+import athleticli.data.Data;
+import athleticli.data.sleep.Sleep;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which finds a sleep entry.
+ */
+public class FindSleepCommand extends FindCommand {
+ private final Logger logger = Logger.getLogger(FindSleepCommand.class.getName());
+
+ /**
+ * Constructor for FindSleepCommand.
+ *
+ * @param date Date of the sleep to be found.
+ */
+ public FindSleepCommand(LocalDate date) {
+ super(date);
+ }
+
+ /**
+ * Returns the sleeps matching the date to be shown to the user.
+ *
+ * @param data The current data.
+ * @return The messages to be shown to the user.
+ * @throws AthletiException If any errors occur in finding the sleep entry.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ logger.info("Finding sleeps on " + date);
+ var resultStream = data.getSleeps()
+ .find(date)
+ .stream()
+ .filter(Sleep.class::isInstance)
+ .map(Sleep.class::cast)
+ .map(Sleep::toString);
+ return Stream.concat(Stream.of(Message.MESSAGE_SLEEP_FIND), resultStream)
+ .toArray(String[]::new);
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/ListSleepCommand.java b/src/main/java/athleticli/commands/sleep/ListSleepCommand.java
new file mode 100644
index 0000000000..1471016d52
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/ListSleepCommand.java
@@ -0,0 +1,58 @@
+package athleticli.commands.sleep;
+
+import java.util.logging.Logger;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.SleepList;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which lists all the sleep records.
+ */
+public class ListSleepCommand extends Command {
+ private static final Logger logger = Logger.getLogger(ListSleepCommand.class.getName());
+
+ /**
+ * Lists all the sleep records in the sleep list.
+ *
+ * @param data The current data containing the sleep list.
+ * @return The message array which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) {
+ logger.info("Executing ListSleepCommand");
+ SleepList sleeps = data.getSleeps();
+ final int size = sleeps.size();
+
+ if (size == 0) {
+ logger.fine("Sleep list is empty");
+ return new String[] {
+ Message.MESSAGE_SLEEP_LIST_EMPTY
+ };
+ }
+
+ return printList(sleeps, size);
+ }
+
+ /**
+ * Prints the list of sleep records.
+ *
+ * @param sleeps The current sleep list.
+ * @param size The size of the sleep list.
+ * @return The message containing list of sleep records which will be shown to the user.
+ */
+ public String[] printList(SleepList sleeps, int size) {
+ logger.fine("Printing sleep list");
+ logger.info("Sleep count: " + sleeps.size());
+ logger.info("Sleep list: " + sleeps.toString());
+
+ String[] output = new String[size+1];
+ output[0] = Message.MESSAGE_SLEEP_LIST;
+ for (int i = 0; i < size; i++) {
+ assert sleeps.get(i) != null : "Sleep record cannot be null";
+ output[i+1] = (i + 1) + ". " + sleeps.get(i).toString();
+ }
+ return output;
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/ListSleepGoalCommand.java b/src/main/java/athleticli/commands/sleep/ListSleepGoalCommand.java
new file mode 100644
index 0000000000..11689f301f
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/ListSleepGoalCommand.java
@@ -0,0 +1,41 @@
+package athleticli.commands.sleep;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.SleepGoalList;
+import athleticli.ui.Message;
+
+import java.util.logging.Logger;
+
+/**
+ * Represents a command which lists all the sleep goals.
+ */
+public class ListSleepGoalCommand extends Command {
+ private static final Logger logger = Logger.getLogger(ListSleepGoalCommand.class.getName());
+
+ /**
+ * Constructor for ListSleepCommand.
+ */
+ public ListSleepGoalCommand() {
+ }
+
+ /**
+ * Lists the sleep goals.
+ *
+ * @param data The current data containing the sleep goal list.
+ * @return The message containing listing of sleep goals which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) {
+ logger.info("Listing sleep goals");
+ SleepGoalList sleepGoals = data.getSleepGoals();
+ int size = sleepGoals.size();
+ String[] output = new String[size + 1];
+ output[0] = Message.MESSAGE_SLEEP_GOAL_LIST;
+ for (int i = 0; i < sleepGoals.size(); i++) {
+ output[i + 1] = (i + 1) + ". " + sleepGoals.get(i).toString(data);
+ }
+ logger.info("Found " + size + " sleep goals");
+ return output;
+ }
+}
diff --git a/src/main/java/athleticli/commands/sleep/SetSleepGoalCommand.java b/src/main/java/athleticli/commands/sleep/SetSleepGoalCommand.java
new file mode 100644
index 0000000000..867b0e1308
--- /dev/null
+++ b/src/main/java/athleticli/commands/sleep/SetSleepGoalCommand.java
@@ -0,0 +1,42 @@
+package athleticli.commands.sleep;
+
+import athleticli.commands.Command;
+import athleticli.data.Data;
+import athleticli.data.sleep.SleepGoal;
+import athleticli.data.sleep.SleepGoalList;
+import athleticli.exceptions.AthletiException;
+import athleticli.ui.Message;
+
+/**
+ * Represents a command which sets a sleep goal.
+ */
+public class SetSleepGoalCommand extends Command {
+ private final SleepGoal sleepGoal;
+
+ /**
+ * Constructor for SetSleepGoalCommand.
+ *
+ * @param sleepGoal Sleep goal to be added.
+ */
+ public SetSleepGoalCommand(SleepGoal sleepGoal) {
+ this.sleepGoal = sleepGoal;
+ }
+
+ /**
+ * Updates the sleep goal list.
+ *
+ * @param data The current data containing the sleep goal list.
+ * @return The message which will be shown to the user.
+ */
+ @Override
+ public String[] execute(Data data) throws AthletiException {
+ SleepGoalList sleepGoals = data.getSleepGoals();
+
+ if (sleepGoals.isDuplicate(sleepGoal.getGoalType(), sleepGoal.getTimeSpan())) {
+ throw new AthletiException(Message.ERRORMESSAGE_DUPLICATE_SLEEP_GOAL);
+ }
+
+ sleepGoals.add(this.sleepGoal);
+ return new String[]{Message.MESSAGE_SLEEP_GOAL_ADDED, this.sleepGoal.toString(data)};
+ }
+}
diff --git a/src/main/java/athleticli/common/Config.java b/src/main/java/athleticli/common/Config.java
new file mode 100644
index 0000000000..9a43bfa87a
--- /dev/null
+++ b/src/main/java/athleticli/common/Config.java
@@ -0,0 +1,27 @@
+package athleticli.common;
+
+import java.time.format.DateTimeFormatter;
+import java.time.format.ResolverStyle;
+
+import static java.util.Locale.ENGLISH;
+
+/**
+ * Defines string literals or configurations used for file storage.
+ */
+public class Config {
+ public static final DateTimeFormatter DATE_TIME_PRETTY_FORMATTER =
+ DateTimeFormatter.ofPattern("MMMM d, " + "yyyy 'at' h:mm a", ENGLISH);
+ public static final DateTimeFormatter DATE_TIME_FORMATTER =
+ DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm").withResolverStyle(ResolverStyle.STRICT)
+ .withLocale(ENGLISH);
+ public static final DateTimeFormatter DATE_FORMATTER =
+ DateTimeFormatter.ofPattern("uuuu-MM-dd").withResolverStyle(ResolverStyle.STRICT)
+ .withLocale(ENGLISH);
+ public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss", ENGLISH);
+ public static final String PATH_ACTIVITY = "./data/activity.txt";
+ public static final String PATH_ACTIVITY_GOAL = "./data/activity_goal.txt";
+ public static final String PATH_SLEEP = "./data/sleep.txt";
+ public static final String PATH_SLEEP_GOAL = "./data/sleep_goal.txt";
+ public static final String PATH_DIET = "./data/diet.txt";
+ public static final String PATH_DIET_GOAL = "./data/diet_goal.txt";
+}
diff --git a/src/main/java/athleticli/data/Data.java b/src/main/java/athleticli/data/Data.java
new file mode 100644
index 0000000000..35fb58ace2
--- /dev/null
+++ b/src/main/java/athleticli/data/Data.java
@@ -0,0 +1,128 @@
+package athleticli.data;
+
+import java.io.IOException;
+
+import athleticli.data.activity.ActivityGoalList;
+import athleticli.data.activity.ActivityList;
+import athleticli.data.diet.DietGoalList;
+import athleticli.data.diet.DietList;
+import athleticli.data.sleep.SleepGoalList;
+import athleticli.data.sleep.SleepList;
+import athleticli.exceptions.AthletiException;
+
+/**
+ * Defines the basic fields and methods of data.
+ */
+public class Data {
+ private static Data dataInstance;
+ private ActivityList activities = new ActivityList();
+ private ActivityGoalList activityGoals = new ActivityGoalList();
+ private DietList diets = new DietList();
+ private DietGoalList dietGoals = new DietGoalList();
+ private SleepList sleeps = new SleepList();
+ private SleepGoalList sleepGoals = new SleepGoalList();
+
+ /**
+ * Returns the singleton instance of `Data`.
+ *
+ * @return The singleton instance of `Data`.
+ */
+ public static Data getInstance() {
+ if (dataInstance == null) {
+ dataInstance = new Data();
+ }
+ return dataInstance;
+ }
+
+ /**
+ * Loads data from files.
+ */
+ public void load() throws AthletiException {
+ activities.load();
+ activityGoals.load();
+ diets.load();
+ dietGoals.load();
+ sleeps.load();
+ sleepGoals.load();
+ }
+
+ /**
+ * Saves data to files.
+ */
+ public void save() throws IOException {
+ activities.save();
+ activityGoals.save();
+ diets.save();
+ dietGoals.save();
+ sleeps.save();
+ sleepGoals.save();
+ }
+
+ /**
+ * Clears all lists.
+ */
+ public void clear() {
+ activities.clear();
+ activityGoals.clear();
+ diets.clear();
+ dietGoals.clear();
+ sleeps.clear();
+ sleepGoals.clear();
+ }
+
+ /**
+ * Get all the objects
+ */
+
+ public ActivityList getActivities() {
+ return activities;
+ }
+
+ public ActivityGoalList getActivityGoals() {
+ return activityGoals;
+ }
+
+ public DietList getDiets() {
+ return diets;
+ }
+
+ public DietGoalList getDietGoals() {
+ return dietGoals;
+ }
+
+ public SleepList getSleeps() {
+ return sleeps;
+ }
+
+ public SleepGoalList getSleepGoals() {
+ return sleepGoals;
+ }
+
+
+ /**
+ * Set all the objects
+ */
+ public void setActivities(ActivityList activities) {
+ this.activities = activities;
+ }
+
+ public void setActivityGoals(ActivityGoalList activityGoals) {
+ this.activityGoals = activityGoals;
+ }
+
+ public void setDiets(DietList diets) {
+ this.diets = diets;
+ }
+
+ public void setDietGoals(DietGoalList dietGoals) {
+ this.dietGoals = dietGoals;
+ }
+
+ public void setSleeps(SleepList sleeps) {
+ this.sleeps = sleeps;
+ }
+
+ public void setSleepGoals(SleepGoalList sleepGoals) {
+ this.sleepGoals = sleepGoals;
+ }
+}
diff --git a/src/main/java/athleticli/data/Findable.java b/src/main/java/athleticli/data/Findable.java
new file mode 100644
index 0000000000..ed0b96af94
--- /dev/null
+++ b/src/main/java/athleticli/data/Findable.java
@@ -0,0 +1,14 @@
+package athleticli.data;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+public interface Findable {
+ /**
+ * Returns a list of objects matching the date.
+ *
+ * @param date The date to be matched.
+ * @return A list of objects matching the date.
+ */
+ public ArrayList find(LocalDate date);
+}
diff --git a/src/main/java/athleticli/data/Goal.java b/src/main/java/athleticli/data/Goal.java
new file mode 100644
index 0000000000..7a29b0af78
--- /dev/null
+++ b/src/main/java/athleticli/data/Goal.java
@@ -0,0 +1,70 @@
+package athleticli.data;
+
+import java.time.LocalDate;
+
+/**
+ * Defines the basic fields and methods for a goal.
+ */
+public abstract class Goal {
+ /**
+ * Defines different types of time spans.
+ */
+ public enum TimeSpan {
+ DAILY(1),
+ WEEKLY(7),
+ MONTHLY(30),
+ YEARLY(365);
+
+ private final int days;
+
+ TimeSpan(int days) {
+ this.days = days;
+ }
+
+ /**
+ * Returns the number of days in the time span.
+ *
+ * @return The number of days in the time span.
+ */
+ public int getDays() {
+ return days;
+ }
+ }
+
+ private TimeSpan timeSpan;
+
+ public Goal(TimeSpan timeSpan) {
+ this.timeSpan = timeSpan;
+ }
+
+ /**
+ * Returns the time span of this goal.
+ *
+ * @return The time span of this goal.
+ */
+ public TimeSpan getTimeSpan() {
+ return timeSpan;
+ }
+
+ /**
+ * Checks whether the date is between the time span.
+ *
+ * @param date The date to be matched.
+ * @param timeSpan The time span of the goal.
+ * @return Whether the date is between the time span.
+ */
+ public static boolean checkDate(LocalDate date, TimeSpan timeSpan) {
+ final LocalDate endDate = LocalDate.now();
+ final LocalDate startDate = endDate.minusDays(timeSpan.getDays() - 1);
+ return !(date.isBefore(startDate) || date.isAfter(endDate));
+ }
+
+ /**
+ * Returns whether the goal is achieved.
+ *
+ * @param data The current data containing all records.
+ * @return Whether the goal is achieved.
+ */
+ public abstract boolean isAchieved(Data data);
+
+}
diff --git a/src/main/java/athleticli/data/StorableList.java b/src/main/java/athleticli/data/StorableList.java
new file mode 100644
index 0000000000..3de1e985eb
--- /dev/null
+++ b/src/main/java/athleticli/data/StorableList.java
@@ -0,0 +1,61 @@
+package athleticli.data;
+
+import static athleticli.ui.Message.MESSAGE_LOAD_EXCEPTION;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import athleticli.exceptions.AthletiException;
+import athleticli.exceptions.WrappedAthletiException;
+import athleticli.storage.Storage;
+
+public abstract class StorableList extends ArrayList {
+ private String path;
+
+ /**
+ * Constructs an empty list with its storage path.
+ */
+ public StorableList(String path) {
+ this.path = path;
+ }
+
+ /**
+ * Saves to a file.
+ */
+ public void save() throws IOException {
+ Storage.save(path, this.stream().map(item -> unparse(item) + "\n"));
+ }
+
+ /**
+ * Loads from a file.
+ */
+ public void load() throws AthletiException {
+ try {
+ Storage.load(path).map(s -> {
+ try {
+ return parse(s);
+ } catch (AthletiException e) {
+ throw new WrappedAthletiException(e);
+ }
+ }).forEachOrdered(this::add);
+ } catch (IOException | WrappedAthletiException e) {
+ throw new AthletiException(String.format(MESSAGE_LOAD_EXCEPTION, path));
+ }
+ }
+
+ /**
+ * Parses a T object from a string.
+ *
+ * @param s The string to be parsed.
+ * @return The T object parsed from the string.
+ */
+ public abstract T parse(String s) throws AthletiException;
+
+ /**
+ * Unparses a T object to a string.
+ *
+ * @param t The T object to be parsed.
+ * @return The string unparsed from the T object.
+ */
+ public abstract String unparse(T t);
+}
diff --git a/src/main/java/athleticli/data/activity/Activity.java b/src/main/java/athleticli/data/activity/Activity.java
new file mode 100644
index 0000000000..9e4f45ba15
--- /dev/null
+++ b/src/main/java/athleticli/data/activity/Activity.java
@@ -0,0 +1,193 @@
+package athleticli.data.activity;
+
+import athleticli.parser.Parameter;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Locale;
+
+import static athleticli.common.Config.DATE_TIME_PRETTY_FORMATTER;
+import static athleticli.common.Config.TIME_FORMATTER;
+import static athleticli.parser.Parameter.ACTIVITY_INDICATOR;
+import static athleticli.parser.Parameter.ACTIVITY_OVERVIEW_SEPARATOR;
+import static athleticli.parser.Parameter.DISTANCE_PREFIX;
+import static athleticli.parser.Parameter.DISTANCE_UNIT_KILOMETERS;
+import static athleticli.parser.Parameter.DISTANCE_UNIT_METERS;
+import static athleticli.parser.Parameter.KILOMETER_IN_METERS;
+import static athleticli.parser.Parameter.SPACE;
+import static athleticli.parser.Parameter.TIME_PREFIX;
+import static athleticli.parser.Parameter.TIME_UNIT_HOURS;
+import static athleticli.parser.Parameter.TIME_UNIT_MINUTES;
+import static athleticli.parser.Parameter.TIME_UNIT_SECONDS;
+
+/**
+ * Represents a physical activity consisting of basic sports data.
+ */
+public class Activity {
+ public static final int COLUMN_WIDTH = 40;
+ private static final String DISTANCE_PRINT_FORMAT = "%.2f";
+ private String caption;
+ private LocalTime movingTime;
+ private int distance;
+ private LocalDateTime startDateTime;
+
+ /**
+ * Generates a new general sports activity with some basic stats.
+ *
+ * @param movingTime Duration of the activity in minutes.
+ * @param distance Distance covered in meters.
+ * @param startDateTime Start date and time of the activity.
+ * @param caption Caption of the activity chosen by the user (e.g., "Morning Run").
+ */
+ public Activity(String caption, LocalTime movingTime, int distance, LocalDateTime startDateTime) {
+ this.movingTime = movingTime;
+ this.distance = distance;
+ this.startDateTime = startDateTime;
+ this.caption = caption;
+ }
+
+ public LocalTime getMovingTime() {
+ return movingTime;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public LocalDateTime getStartDateTime() {
+ return startDateTime;
+ }
+
+ /**
+ * Returns a single line summary of the activity.
+ *
+ * @return a string representation of the activity.
+ */
+ @Override
+ public String toString() {
+ String movingTimeOutput = generateShortMovingTimeStringOutput();
+ String distanceOutput = generateDistanceStringOutput();
+ String startDateTimeOutput = generateStartDateTimeStringOutput();
+
+ String output = String.join(ACTIVITY_OVERVIEW_SEPARATOR, caption, distanceOutput, movingTimeOutput,
+ startDateTimeOutput);
+ return ACTIVITY_INDICATOR + SPACE + output;
+ }
+
+ /**
+ * Returns distance in user-friendly output format.
+ * Assumes distance is given in meters.
+ * If the distance is less than 1 km, the distance is displayed in meters.
+ *
+ * @return a string representation of the distance.
+ */
+ public String generateDistanceStringOutput() {
+ StringBuilder output = new StringBuilder(DISTANCE_PREFIX);
+ if (distance < KILOMETER_IN_METERS) {
+ output.append(distance);
+ output.append(DISTANCE_UNIT_METERS);
+ } else {
+ double distanceInKm = distance / 1000.0;
+ output.append(String.format(Locale.ENGLISH, DISTANCE_PRINT_FORMAT, distanceInKm));
+ output.append(DISTANCE_UNIT_KILOMETERS);
+ }
+ return output.toString();
+ }
+
+ /**
+ * Returns moving time in user-friendly output format.
+ *
+ * @return a string representation of the moving time.
+ */
+ public String generateMovingTimeStringOutput() {
+ return TIME_PREFIX + movingTime.format(TIME_FORMATTER);
+ }
+
+ /**
+ * Returns a short representation of the moving time with the format depending on the duration.
+ * Format is "Xh Ym" if hours are present, otherwise "Ym Zs".
+ *
+ * @return a string representation of the moving time.
+ */
+ public String generateShortMovingTimeStringOutput() {
+ StringBuilder output = new StringBuilder(TIME_PREFIX);
+ if (movingTime.getHour() > 0) {
+ output.append(movingTime.getHour()).append(TIME_UNIT_HOURS + SPACE);
+ output.append(movingTime.getMinute()).append(TIME_UNIT_MINUTES);
+ } else {
+ output.append(movingTime.getMinute()).append(TIME_UNIT_MINUTES + SPACE);
+ output.append(movingTime.getSecond()).append(TIME_UNIT_SECONDS);
+ }
+ return output.toString();
+ }
+
+ /**
+ * Returns start date and time in user-friendly output format.
+ *
+ * @return a string representation of the start date and time.
+ */
+ public String generateStartDateTimeStringOutput() {
+ return startDateTime.format(DATE_TIME_PRETTY_FORMATTER);
+ }
+
+ /**
+ * Returns a detailed summary of the activity.
+ *
+ * @return a multiline string representation of the activity.
+ */
+ public String toDetailedString() {
+ String startDateTimeOutput = generateStartDateTimeStringOutput();
+ String movingTimeOutput = generateMovingTimeStringOutput();
+ String distanceOutput = generateDistanceStringOutput();
+
+ String header = "[Activity - " + getCaption() + " - " + startDateTimeOutput + "]";
+ String firstRow = formatTwoColumns("\t" + distanceOutput, movingTimeOutput, COLUMN_WIDTH);
+
+ return String.join(System.lineSeparator(), header, firstRow);
+ }
+
+ /**
+ * Formats two strings into two columns of equal width.
+ * If a string is longer than the specified columnWidth, it will exceed the column.
+ *
+ * @param left String to be placed in the left column.
+ * @param right String to be placed in the right column.
+ * @param columnWidth Width of each column, should be a positive Integer.
+ * @return a formatted string with two columns of equal width.
+ */
+ public String formatTwoColumns(String left, String right, int columnWidth) {
+ return String.format("%-" + columnWidth + "s%s", left, right);
+ }
+
+ /**
+ * Returns a string representation of the activity used for storing the data.
+ *
+ * @return a string representation of the activity.
+ */
+ public String unparse() {
+ return Parameter.ACTIVITY_STORAGE_INDICATOR + SPACE + getCaption() +
+ SPACE + Parameter.DURATION_SEPARATOR + getMovingTime().format(TIME_FORMATTER) +
+ SPACE + Parameter.DISTANCE_SEPARATOR + getDistance() +
+ SPACE + Parameter.DATETIME_SEPARATOR + getStartDateTime();
+ }
+
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ public void setMovingTime(LocalTime movingTime) {
+ this.movingTime = movingTime;
+ }
+
+ public void setDistance(int distance) {
+ this.distance = distance;
+ }
+
+ public void setStartDateTime(LocalDateTime startDateTime) {
+ this.startDateTime = startDateTime;
+ }
+}
diff --git a/src/main/java/athleticli/data/activity/ActivityChanges.java b/src/main/java/athleticli/data/activity/ActivityChanges.java
new file mode 100644
index 0000000000..319358e140
--- /dev/null
+++ b/src/main/java/athleticli/data/activity/ActivityChanges.java
@@ -0,0 +1,72 @@
+package athleticli.data.activity;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import athleticli.data.activity.Swim.SwimmingStyle;
+
+/**
+ * Represents an object that tracks changes to an activity.
+ */
+public class ActivityChanges {
+ private String caption;
+ private int distance;
+ private LocalTime duration;
+ private LocalDateTime startDateTime;
+ private int elevation;
+ private SwimmingStyle swimmingStyle;
+
+ /**
+ * Constructs an empty ActivityChanges object.
+ */
+ public ActivityChanges() {
+
+ }
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public void setDistance(int distance) {
+ this.distance = distance;
+ }
+
+ public LocalTime getDuration() {
+ return duration;
+ }
+
+ public void setDuration(LocalTime duration) {
+ this.duration = duration;
+ }
+
+ public LocalDateTime getStartDateTime() {
+ return startDateTime;
+ }
+
+ public void setStartDateTime(LocalDateTime startDateTime) {
+ this.startDateTime = startDateTime;
+ }
+
+ public int getElevation() {
+ return elevation;
+ }
+
+ public void setElevation(int elevation) {
+ this.elevation = elevation;
+ }
+
+ public SwimmingStyle getSwimmingStyle() {
+ return swimmingStyle;
+ }
+
+ public void setSwimmingStyle(SwimmingStyle swimmingStyle) {
+ this.swimmingStyle = swimmingStyle;
+ }
+}
diff --git a/src/main/java/athleticli/data/activity/ActivityGoal.java b/src/main/java/athleticli/data/activity/ActivityGoal.java
new file mode 100644
index 0000000000..87474c69e6
--- /dev/null
+++ b/src/main/java/athleticli/data/activity/ActivityGoal.java
@@ -0,0 +1,131 @@
+package athleticli.data.activity;
+
+import athleticli.data.Data;
+import athleticli.data.Goal;
+import athleticli.parser.Parameter;
+
+/**
+ * Represents an activity goal.
+ */
+public class ActivityGoal extends Goal {
+ public enum GoalType {
+ DISTANCE, DURATION
+ }
+ public enum Sport {
+ RUNNING, CYCLING, SWIMMING, GENERAL
+ }
+
+ private int targetValue;
+ private final GoalType goalType;
+ private final Sport sport;
+
+ /**
+ * Constructs an activity goal.
+ *
+ * @param timeSpan Time span of the activity goal.
+ * @param goalType Goal type of the activity goal.
+ * @param sport Sport related to the activity goal.
+ * @param targetValue Target value of the activity goal.
+ */
+ public ActivityGoal(TimeSpan timeSpan, GoalType goalType, Sport sport, int targetValue) {
+ super(timeSpan);
+ this.targetValue = targetValue;
+ this.goalType = goalType;
+ this.sport = sport;
+ }
+
+ /**
+ * Examines whether the activity goal is achieved.
+ *
+ * @param data Data containing the activity list.
+ * @return Whether the activity goal is achieved.
+ */
+ @Override
+ public boolean isAchieved(Data data) throws IllegalStateException {
+ return getCurrentValue(data) >= targetValue;
+ }
+
+ /**
+ * Returns the current value of the activity goal metric.
+ *
+ * @param data Data containing the activity list.
+ * @return Current value of the activity goal metric.
+ * @throws IllegalStateException If the goal type is not supported.
+ */
+ public int getCurrentValue(Data data) {
+ ActivityList activities = data.getActivities();
+ Class> activityClass = getActivityClass();
+
+ switch (goalType) {
+ case DISTANCE:
+ return activities.getTotalDistance(activityClass, this.getTimeSpan());
+ case DURATION:
+ int totalDuration = activities.getTotalDuration(activityClass, this.getTimeSpan());
+ return convertToMinutes(totalDuration);
+ default:
+ throw new IllegalStateException("Unexpected value: " + goalType);
+ }
+ }
+
+ /**
+ * Converts the given seconds to minutes.
+ *
+ * @param seconds Seconds to be converted.
+ * @return Minutes converted from the given seconds.
+ */
+ private int convertToMinutes(int seconds) {
+ return seconds / Parameter.MINUTE_IN_SECONDS;
+ }
+
+ public void setTargetValue(int targetValue) {
+ this.targetValue = targetValue;
+ }
+
+ /**
+ * Returns the class of the activity associated with the activity goal.
+ *
+ * @return The class of the activity.
+ */
+ public Class> getActivityClass() {
+ switch (this.sport) {
+ case RUNNING:
+ return Run.class;
+ case CYCLING:
+ return Cycle.class;
+ case SWIMMING:
+ return Swim.class;
+ case GENERAL:
+ return Activity.class;
+ default:
+ throw new IllegalStateException("Unexpected value: " + this.sport);
+ }
+ }
+
+ /**
+ * Returns the string representation of the activity goal including progress information.
+ *
+ * @param data Data containing the activity list.
+ * @return The string representation of the activity goal.
+ */
+ public String toString(Data data) {
+ String goalTypeString = goalType.name().toLowerCase();
+ String sportString = sport.name().toLowerCase();
+ String timeSpanString = getTimeSpan().name().toLowerCase();
+
+ return String.format("%s %s %s: %d / %d", timeSpanString, sportString, goalTypeString,
+ getCurrentValue(data), targetValue);
+ }
+
+ public GoalType getGoalType() {
+ return goalType;
+ }
+
+ public Sport getSport() {
+ return sport;
+ }
+
+ public int getTargetValue() {
+ return targetValue;
+ }
+
+}
diff --git a/src/main/java/athleticli/data/activity/ActivityGoalList.java b/src/main/java/athleticli/data/activity/ActivityGoalList.java
new file mode 100644
index 0000000000..e5e813b9a5
--- /dev/null
+++ b/src/main/java/athleticli/data/activity/ActivityGoalList.java
@@ -0,0 +1,61 @@
+package athleticli.data.activity;
+
+import athleticli.data.Goal;
+import athleticli.data.StorableList;
+import athleticli.exceptions.AthletiException;
+import athleticli.parser.ActivityParser;
+import athleticli.parser.Parameter;
+
+import static athleticli.common.Config.PATH_ACTIVITY_GOAL;
+
+/**
+ * Represents a list of activity goals.
+ */
+public class ActivityGoalList extends StorableList {
+ /**
+ * Constructs an activity goal list.
+ */
+ public ActivityGoalList() {
+ super(PATH_ACTIVITY_GOAL);
+ }
+
+ /**
+ * Parses an activity goal from a string.
+ *
+ * @param arguments The string to be parsed.
+ * @return The activity goal parsed from the string.
+ */
+ @Override
+ public ActivityGoal parse(String arguments) throws AthletiException {
+ return ActivityParser.parseActivityGoal(arguments);
+ }
+
+ /**
+ * Unparses an activity goal to a string.
+ * Example output: "sport/running type/distance period/weekly target/8000".
+ *
+ * @param activityGoal Activity goal to be parsed.
+ * @return The string unparsed from the activity goal.
+ */
+ @Override
+ public String unparse(ActivityGoal activityGoal) {
+ return Parameter.SPORT_SEPARATOR + activityGoal.getSport()
+ + Parameter.SPACE + Parameter.TYPE_SEPARATOR + activityGoal.getGoalType()
+ + Parameter.SPACE + Parameter.PERIOD_SEPARATOR + activityGoal.getTimeSpan()
+ + Parameter.SPACE + Parameter.TARGET_SEPARATOR + activityGoal.getTargetValue();
+ }
+
+ /**
+ * Checks if there is a duplicate activity goal with the same goal type, sport and timespan.
+ *
+ * @param goalType Goal type of the activity goal.
+ * @param sport Sport associated with the activity goal.
+ * @param timeSpan Time span of the activity goal.
+ * @return Whether the activity goal is a duplicate.
+ */
+ public boolean isDuplicate(ActivityGoal.GoalType goalType, ActivityGoal.Sport sport, Goal.TimeSpan timeSpan) {
+ return this.stream().anyMatch(activityGoal -> activityGoal.getGoalType() == goalType
+ && activityGoal.getSport() == sport
+ && activityGoal.getTimeSpan() == timeSpan);
+ }
+}
diff --git a/src/main/java/athleticli/data/activity/ActivityList.java b/src/main/java/athleticli/data/activity/ActivityList.java
new file mode 100644
index 0000000000..8a22f99bbb
--- /dev/null
+++ b/src/main/java/athleticli/data/activity/ActivityList.java
@@ -0,0 +1,147 @@
+package athleticli.data.activity;
+
+import static athleticli.common.Config.PATH_ACTIVITY;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import athleticli.data.Findable;
+import athleticli.data.StorableList;
+import athleticli.data.Goal;
+import athleticli.exceptions.AthletiException;
+import athleticli.parser.ActivityParser;
+import athleticli.parser.Parameter;
+import athleticli.ui.Message;
+
+/**
+ * Represents a list of activities.
+ */
+public class ActivityList extends StorableList implements Findable {
+ /**
+ * Constructs an empty activity list.
+ */
+ public ActivityList() {
+ super(PATH_ACTIVITY);
+ }
+
+ /**
+ * Returns a list of activities matching the date.
+ *
+ * @param date The date to be matched.
+ * @return A list of activities matching the date.
+ */
+ @Override
+ public ArrayList