diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index fd8c44d086..2fee075d9d 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -33,18 +33,4 @@ jobs:
- name: Build and check with Gradle
run: ./gradlew check
- - name: Perform IO redirection test (*NIX)
- if: runner.os == 'Linux'
- working-directory: ${{ github.workspace }}/text-ui-test
- run: ./runtest.sh
-
- - name: Perform IO redirection test (MacOS)
- if: always() && runner.os == 'macOS'
- working-directory: ${{ github.workspace }}/text-ui-test
- run: ./runtest.sh
-
- - name: Perform IO redirection test (Windows)
- if: always() && runner.os == 'Windows'
- working-directory: ${{ github.workspace }}/text-ui-test
- shell: cmd
- run: runtest.bat
\ No newline at end of file
+
diff --git a/.gitignore b/.gitignore
index 2873e189e1..f3c908fdcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# IDEA files
/.idea/
/out/
@@ -15,3 +16,34 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+
+text-ui-test/EXPECTED.TXT
+text-ui-test/input.txt
+text-ui-test/runtest.sh
+text-ui-test/runtest.bat
+data/
+=======
+# IDEA files
+/.idea/
+/out/
+/*.iml
+
+# Gradle build files
+/.gradle/
+/build/
+src/main/resources/docs/
+
+# MacOS custom attributes files created by Finder
+.DS_Store
+*.iml
+bin/
+
+/text-ui-test/ACTUAL.TXT
+text-ui-test/EXPECTED-UNIX.TXT
+
+text-ui-test/EXPECTED.TXT
+text-ui-test/input.txt
+text-ui-test/runtest.sh
+text-ui-test/runtest.bat
+data/workoutRecording.txt
+>>>>>>> 39f25ad9df885da80c4d85dbb509a2975f9d8e3e
diff --git a/README.md b/README.md
index f82e2494b7..67ba862d68 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# Fitnees checker
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.
diff --git a/build.gradle b/build.gradle
index d5e548e85f..4ed3f9a76c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,8 +10,11 @@ repositories {
}
dependencies {
- testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
- testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+ implementation 'junit:junit:4.13.1'
+ implementation 'junit:junit:4.13.1'
+ implementation 'org.testng:testng:7.1.0'
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.2'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.9.2'
}
test {
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..b0891c1f4a 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,14 @@
# 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://via.placeholder.com/100.png?text=Photo) | Richard Kurniawan | [Github](https://github.com/Richardtok) | [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) | Caleb Chan Jia Le | [Github](https://github.com/calebcjl) | [Portfolio](docs/team/johndoe.md) |
+
+| ![](https://via.placeholder.com/100.png?text=Photo) | Guillaume Gerony | [Github](https://github.com/guillaume-grn) | [Portfolio](docs/team/johndoe.md) |
+
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..ffb99c21e5 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,29 +1,422 @@
-# Developer Guide
+# Fitz - Developer Guide
+
+## Table of Contents
+
+
+* [Fitz - Developer Guide](#fitz---developer-guide)
+ * [Table of Contents](#table-of-contents)
+ * [Acknowledgements](#acknowledgements)
+ * [Product Scope](#product-scope)
+ * [Target User Profile](#target-user-profile)
+ * [Value Proposition](#value-proposition)
+ * [Back to table of contents](#back-to-table-of-contents)
+ * [Design](#design)
+ * [Architecture](#architecture)
+ * [Duke](#duke)
+ * [UI Component](#ui-component)
+ * [Command Component](#command-component)
+ * [Storage Component](#storage-component)
+ * [Calories Component](#calories-component)
+ * [Workout Component](#workout-component)
+ * [Implementation](#implementation)
+ * [Implementation of Workout](#implementation-of-workout)
+ * [Start Workout](#start-workout)
+ * [Add Exercise](#add-exercise)
+ * [List workout](#list-workout)
+ * [View workout](#view-workout)
+ * [Delete Command](#delete-command)
+ * [Count Command](#count-command)
+ * [Implementation of Calories](#implementation-of-calories)
+ * [Adding Calories](#adding-calories)
+ * [Listing Calorie Dates](#listing-calorie-dates)
+ * [Viewing Calories in a Day](#viewing-calories-in-a-day)
+ * [Deleting Calories Date](#deleting-calories-date)
+ * [Exit command](#exit-command)
+ * [User Stories](#user-stories)
+ * [V1.0](#v10)
+ * [V2.0](#v20)
+ * [Non-Functional Requirements](#non-functional-requirements)
+ * [Glossary](#glossary)
+ * [Instructions for manual testing](#instructions-for-manual-testing)
+
+
## Acknowledgements
+The format of this developer guide was adapted from
+[SE-EDU AddressBook Level 3 Developer Guide](https://se-education.org/addressbook-level3/DeveloperGuide.html).
+
+## Product Scope
+The purpose of this app is to help users record their workouts on the current day and track their previous workouts.
+Additionally, the app will allow users to record their daily food intake to achieve their fitness goals.
+
+
+### Target User Profile
+* Fitness enthusiasts who regularly go to the gym and perform various exercises to maintain their fitness
+* Individuals who want to lose weight
+* People who want to build muscle strength and are looking for an easy
+and convenient way to record and track their progress towards their fitness goals.
+* Fitness enthusiasts and athletes who are looking for an easy and convenient way to
+track their daily workouts and calories intake
+* People who want to monitor their progress and achieve their fitness goals.
+
+### Value Proposition
+Our app is a comprehensive workout and calories tracking solution that helps fitness enthusiasts
+and individuals achieve their fitness goals.
+With features like tracking of workouts and daily calories' intake,
+our app makes it easy for users to stay motivated and track their progress towards their fitness goals.
+
+
+###### [Back to table of contents](#table-of-contents)
+
+
+## Design
+
+### Architecture
+
+The Architecture Diagram shown above shows the design of FITZ with its components.
+The following are highlighting parts
+* There are 3 Storages class that related to workout and calories.
+ They are `CalorieTrackerStorage`, `FoodDictionaryStorage` and `WorkoutListStorage`
+* All the exception messages will be shown in `Ui`
+
+
+
+
+
+
+
+### Duke
+`Duke` is the class that contains main method
+which are responsible for `Ui`, `Storage`, `Parser`, `Exception` and `Command`.
+Once the program start, `storage` and `Ui` will be initialized.
+The following statements describe what will happen after the program start:
+
+ * `storage` and `Ui` will be initialized.
+ * `Ui`: show the welcome message
+ * `Storage`: load the exiting data to the system.
+
+Afterwards, it takes in user commands and continues to do so until the user inputs the exit command.
+Whenever a user enters a command, the Ui reads it and passes it to `Duke`, which in turn sends it to the `Parser` class for parsing.
+If the command is determined to be valid, it is then sent to the `Command` class for processing and returned to `Duke` for execution.
+`Duke` displays valid responses to the user via the `Ui`, and stores the data in Storage. If the command is invalid, `Duke` displays an appropriate error message instead.
+The following diagram illustrate how the `Duke` class work.
+
+
+
+
+
+### UI Component
+
+Below is the class diagram for the `Ui` component, which is responsible for managing the retrieval of user input
+and displaying relevant information and error messages within the application.
+`getUserInput()` methods is used to get the user input
+and all the methods that related to `showMessage` are used for printing out the error message or the relevant information
+which will correspond to the user behaviour.
+
+
+
+
+
+
+### Command Component
+
+The picture below shows the lower level design of Command component of the software.
+Generally, the commands class in `workoutcommnds` ,`caloriescommands`, and `errorcommands` package
+inherit from `Command` class. Besides, `ExitCommand` also inherit from `Command` class。
+
+
+
+
+
+With this understanding, it can be seen that there is an inheritance relationship between
+the `Commands` class and its subclasses. The following class diagram provides more details within each class,
+and it is evident that all subclasses inherit the `execute()` method from the Command class.
+
+
+These are the further explanation for each class:
+* Under caloriescommands package:
+ * `AddCaloriesCommand`: It is responsible for taking the food name, date and calories.
+ * `DeleteCaloriesCommand`: It is responsible for deleting the record for calories in one specific day
+ * `ListCaloriesCommand`: It is responsible to show the list of dates that had been entered by the user before.
+ * `ViewCaloriesCommand`: Compare to List feature, view function aims to show more detailed information in one specific day.
+ * `HelpCaloriesCommand`: It is responsible to show the guidance for users if they are not familiar with the calories commands.
+* Under workoutcommands package:
+ * `StartWorkoutCommand`: This class is responsible for user to add their workout in current day. And it will take in workout name.
+ * `AddExerciseCommand`: This class contains the operation to add the exercise to the workouts.
+ * `ListWorkoutCommand`: This class contains the operation to show list of dates.
+ * `ViewWorkoutCommand`: This class contains the operation to view the workouts information for a specific day.
+ * `DeleteWorkoutCommand`: This class contains the operation to delete the workouts for one day
+ * `HelpWorkoutCommand`: Same as HelpCaloriesCommand, but this one show the workout commands.
+ * `CountSetsRepsCommand`: This class contains the operation to get the all number of sets and rps within one week.
+
+
+
+
+
+### Storage Component
+
+Fitz contains three separate storages. `CaloriesTrackerStorage`
+and `FoodDictionaryStorage` are used for saving and loading calories record
+while `WorkoutListStorage` is used to save and load the workouts record. The class diagram shows more details.
+Once the user exit program, the date will be store to `fooddic.txt`, `calorietracker.txt`, `workoutlist.txt` respectively
+and these files are under data folder.
+
+One thing to take note is that The difference between `FoodDictionaryStorage` and `CaloriesStorage` is that
+`CaloriesTrackerStorage `will store the food based on the date they entered.
+However, `FoodDictionaryStorage` will store all the food and calories that had been entered by the user before.
+
+
+
+
+
+### Calories Component
+
+The class diagram below illustrate how the `Calories` component interact with each others.
+Basically, `Calories` Component consist of four main classes which are `Food`, `FoodList`, `FoodDictionary`
+and `CaloriesTracker`.
+The following are the explanation for each of them:
+ * `Food`: It is a class which contains the food name and its related calories.
+ * `FoodList`: It consists of list of `Food`.
+ * `FoodDictionary`: It represents a dictionary that maps food to its calories
+ and it also read the data from `FoodDictionaryStorage`.
+ This class mainly use for retrieving food and it relevant calories that have been entered.
+ * FoodTracker: It has the dependency on `FoodDictionary`
+ because it is required to check if a food item and its calories exist in dictionary
+ Besides, it also read the data from `CaloriesTrackerStorage` so that users can track their calories consumption for other days.
+ From the diagram, it shows that FoodList consist of a list of Food and FoodDictionary has a dependency of FoodList.
+
+
+
+
+
+### Workout Component
+The class diagram below illustrates how the Workout component interact with each others.
+From the diagram, it is clear to see that the Workout consists of a list of exercises
+and the WorkoutList consists of list of Workout.
+
+
+
+
+
+## Implementation
+
+### Implementation of Workout
+
+#### Start Workout
+
+The start mechanism is facilitated by `StartWorkoutCommand`.
+It extends `Command` and modifies the execute function to start a new Workout and add it to the workout list.
+
+
+Given below is an example usage scenario and how the start mechanism behaves at each step.
+
+Step 1. When `StartWorkoutCommand#execute()` is called, `StartWorkoutCommand` calls `WorkList#getCurrentWorkout()`
+to get `currentWorkoutIndex`.
+
+Step 2. If `currentWorkoutIndex` indicates that there is an ongoing workout, `StartWorkoutCommand` returns a message
+to prompt the user to end the workout first.
+
+Step 3. If `currentWorkoutIndex` indicates that there is no ongoing workout. It calls
+`WorkList#startWorkout(date, Workoutname)` to start a new workout.
+
+Step 4. This initialises a new `Workout`, workout, and adds it to the workout list with `WorkList.add(workout)`.
+It then lets the user know that a new workout has started.
+
+#### Add Exercise
+
+The add mechanism is facilitated by `AddExerciseCommand`.
+It extends `Command` and modifies the execute function to add an exercise to the current workout.
+
+
+
+Given below is an example usage scenario and how the add mechanism behaves at each step.
+
+Step 1. When `AddExerciseCommand#execute()` is called, `AddExerciseCommand` calls `WorkList#getCurrentWorkout()`
+to get `currentWorkoutIndex`.
+
+Step 2. If `currentWorkoutIndex` indicates that there is no ongoing workout, `AddExerciseCommand` returns a message
+to prompt the user to start a workout first.
-{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+Step 3. If `currentWorkoutIndex` indicates that there is an ongoing workout. It calls
+`WorkList#getCurrentWorkout()` and `Workout#addExercise` to add the `Exercise`, toAdd, to the current workout.
+It then lets the user know that the exercise has been added.
-## Design & implementation
+#### End Workout
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+The end mechanism is facilitated by `EndWorkoutCommand`.
+It extends `Command` and modifies the execute function to end the current workout.
+
-## Product scope
-### Target user profile
+Given below is an example usage scenario and how the start mechanism behaves at each step.
-{Describe the target user profile}
+Step 1. When `EndWorkoutCommand#execute()` is called, `EndWorkoutCommand` calls `WorkList#getCurrentWorkout()`
+to get `currentWorkoutIndex`.
-### Value proposition
+Step 2. If `currentWorkoutIndex` indicates that there is no ongoing workout, `EndWorkoutCommand` returns a message
+that there is no ongoing workout to end.
-{Describe the value proposition: what problem does it solve?}
+Step 3. If `currentWorkoutIndex` indicates that there is an ongoing workout. It resets the `currentWorkoutIndex` with
+`WorkoutList#setCurrentWorkoutIndex(NO_CURRENT_WORKOUT)` indicating that there is no longer any ongoing workouts, and
+returns a message that the workout has ended.
+
+#### List workout
+
+The list mechanism is facilitated by 'Parser', 'ListCommand', 'WorkoutList' and 'UI', where a Workout object will be
+deleted according to the command inputted by the user and removed from the workout list.
+
+
+
+Below is an example usage scenario and how the List mechanism behaves at each step:
+
+Step 1: Assume that the user has already added a workout on 21/03/23 into the WorkoutList using the following command, /start 21/03/23
+Assume the user add another workout on 22/03/23 by entering /start 22/03/23
+
+Step 2: The user input of /list will be taken in for the parser and an object of class ListCommand will be returned.
+
+Step 3: The execute method in the ListWorkoutCommand class that is overrides will be called and print out all the dates that while iterating the workoutList.
+
+#### View workout
+
+The View component is facilitated by `Parser`,`Ui`,`WorkoutList`,`Command` and `ViewCommand`, where the user will
+enter a specific workout date and the number of exercises on that date will be displayed
+
+Below are the specific steps on how to use the view function and how the mechanism will flow:
+
+* Step 1: We will assume that the user has started a workout on two specific dates, `11/02/22` which was added with the following command `/start 11/02/22`
+ and `12/02/22`, which was added with the following command `/start 12/02/22`.
+* Step 2: The user will then use the following command `/view 11/02/22` will be taken into the parser
+ and will return a list of exercises done on that specified date.
+
+
+
+#### Delete Command
+The deletion mechanism is facilitated by 'Parser', 'WorkoutParser', 'DeleteWorkoutCommand', 'WorkoutList' and 'UI', where a Workout object will be deleted according to the command inputted by the user and removed from the workout list.
+
+
+
+Below is an example usage scenario and how the deletion mechanism behaves at each step:
+
+Step 1: Assume that the user has already added a workout into the WorkoutList using the following command, /wstart upper body training
+
+Step 2: The user input of /wdelete 1 will be taken in for the parser and an object of class DeleteCommand will be returned.
+
+Step 3: The execute method in the DeleteCommand class that is overrides will be called with parameter index and will remove the matching workout from workoutList. It will then return a successful message that will be displayed to the user.
+
+#### Count Command
+The count mechanism is facilitated by 'Parser', 'WorkoutParser', 'DeleteWorkoutCommand', 'WorkoutList' and 'UI', where a recap of the total sets and reps done for each exercise will be displayed according to the command inputted by the user.
+
+
+
+Below is an example usage scenario and how the count mechanism behaves at each step:
+
+Step 1: Assume that the user has already added at least one workout into the WorkoutList using the following command, /wstart upper body training on the 10/04/23.
+
+Step 2: The user input of /wcount 10/04/23 will be taken in for the parser and an object of class CountSetsRepsCommand will be returned.
+
+Step 3: The execute method in the CountSetsRepsCommand class that is overrides will be called with parameter dayInSpecificWeekDate and will agglomerate all the workouts done during the specific week. It will then create a list of exercises with all the distinct exercises and grouped by name. Finally, the reps and sets will be summed and the recap will be displayed to the user.
+
+### Implementation of Calories
+
+#### Adding Calories
+The AddCaloriesCommand component is facilitated by `Parser`,`CalorieParser`,`Ui`,`CalorieTracker`,`Food`,`FoodDictionary`,`Foodlist`,
+`Command` and `AddCaloriesCommand`, where the user will
+enter a FOOD_NAME and CALORIE_COUNT, and it will be recorded into the `CalorieTracker`
+
+Below are the specific steps on how to use the AddCaloriesCommand function and how the mechanism will flow:
+
+* Step 1: We will assume that the user has started the App, the user will then type it in this format
+`/cadd FOOD_NAME CALORIE COUNT` for example `/cadd chicken 100`. The input will be taken into the parser
+ and will return a string mentioning that it has been added.
+
+
+
+
+
+#### Listing Calorie Dates
+The ListCalories component is facilitated by `Parser`,`CalorieParser`,`Ui`,`CalorieTracker`,`Food`,`FoodDictionary`,`Foodlist`,
+`Command` and `ListCaloriesCommand`, where the user will
+enter a command `/clist` and it will return all the dates in the list
+
+Below are the specific steps on how to use the ListCaloriesCommand function and how the mechanism will flow:
+
+* Step 1: We will assume that the user has started the App and added calories via `/cadd chicken 100`.
+* Step 2: The user will then type it in this format `/clist`. The input will be taken into the parser
+and will return a string listing out the dates.
+
+
+
+
+
+#### Viewing Calories in a Day
+
+The ViewCaloriesCommand component is facilitated by `Parser`,`CalorieParser`,`Ui`,`CalorieTracker`,`Food`,`FoodDictionary`,`Foodlist`,
+`Command` and `ViewCaloriesCommand`, where the user will
+enter a command `/cview INDEX` and it will return all the dates in the list
+
+Below are the specific steps on how to use the ListCaloriesCommand function and how the mechanism will flow:
+
+* Step 1: We will assume that the user has started the App and added calories via `/cadd chicken 100`.
+* Step 2: The user will then type it in this format `/cview INDEX` e.g `/cview 1`. The input will be taken into the parser
+ and will return a string listing out the foods that were eaten on that day.
+
+
+
+
+
+#### Deleting Calories Date
+
+The DeleteCaloriesCommand component is facilitated by `Parser`,`CalorieParser`,`Ui`,`CalorieTracker`,`Food`,`FoodDictionary`,`Foodlist`,
+`Command` and `DeleteCaloriesCommand`, where the user will
+enter a command `/cdelete INDEX` and it will return all the dates in the list
+
+Below are the specific steps on how to use the ListCaloriesCommand function and how the mechanism will flow:
+
+* Step 1: We will assume that the user has started the App and added calories via `/cadd chicken 100`.
+* Step 2: The user will then type it in this format `/cdelete INDEX` e.g `/cdelete 1`. The input will be taken into the parser
+ and will return a string confirming the deletion of the date.
+
+
+
+
+
+### Exit command
+
+The exit mechanism is facilitated by `Duke`, `Parser`, and `ExitCommand`.
+
+
+
+Below is an example usage scenario and how the deletion mechanism behaves at each step:
+
+Step 1: As the program runs `Duke#executeCommandUntilExit()`, it will get user input with `Ui#getUserInput()`
+which returns the userInput.
+
+Step 2: The userInput will then be parsed with `Parser#parrseCommand(userInput)` and it will return the command
+based on the command the user entered.
+
+Step 3: If command is an instance of `ExitCommand`, the user has entered the exit command. This will break the
+loop and the program will exit.
## 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|
+### V1.0
+
+| As a | I want to ... | So that I can ... |
+|----------|---------------------------------------------------------------------------|-----------------------------------|
+| user | record down my exercise for each workout | check the workout whenever l want |
+| new user | know how to use the app | |
+| user | know which days l have done exercise | have clear insight of myself |
+| user | know how many workouts l have done for a day | make exercise plan based on this |
+| user | remove some workouts that have been incorrectly recorded | |
+
+### V2.0
+
+| As a | I want to ... | So that I can ... |
+|------|-----------------------------------------------------------|--------------------------------------------|
+| user | know the amount of calories I consume each day | control the calories intake |
+| user | know the workout l have done in last month | make a exercise plan for next month |
+| user | know the frequency l do exercise for one month | inspire myself |
+| user | know the amount of calories I have consumed for one month | have better insights of my calories intake |
## Non-Functional Requirements
@@ -33,6 +426,8 @@
* *glossary item* - Definition
+
+
## 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}
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..29e3ac9f68 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,6 +1,7 @@
-# Duke
+# Fitness Checker
-{Give product intro here}
+The product will be able to keep track of the user's daily exercise and workouts. This product
+will also be able to keep track calories consumed to be mindful of the user's diet
Useful links:
* [User Guide](UserGuide.md)
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..2ebc6150e2 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,322 @@
-# User Guide
+# User Guide
+# ❚·══·❚ Fitz ❚·══·❚
+
+Fitz is a fitness tracker for users who are active and trying to keep fit or hit a fitness goal.
+This app will be displayed and used in CLI format. It is targeted toward those who prefer to use CLI over GUI.
+The product will be able to keep track of the user's progress, daily exercises, and workouts.
+This helps with planning future exercises.
+
+## Table of Contents
+- [Introduction](#introduction)
+- [Quick Start](#quick-start)
+ - [Setting Up](#setting-up)
+- [Features](#features)
+ - [Start a workout: /wstart](#start-a-workout-wstart)
+ - [Add exercises to current workout: /wadd](#add-exercises-to-current-workout-wadd)
+ - [List workout dates: /wlist](#list-workout-dates-wlist)
+ - [View workout details: /wview](#view-a-workout-wview)
+ - [Delete workout record: /wdelete](#delete-a-workout-wdelete)
+ - [Count sets and reps for a week: /wcount](#count-sets-and-reps-over-a-week-wcount)
+ - [End current workout: /wend](#end-a-workout-wend)
+ - [Viewing workout help: /whelp](#viewing-workout-help-whelp)
+ - [Add calories consumed: /cadd](#add-calories-consumed-cadd)
+ - [List all calories consumption: /clist](#list-all-calorie-consumption-clist)
+ - [View calorie consumption of day: /cview](#view-calorie-consumption-of-day-cview)
+ - [Delete calories record: /cdelete](#delete-a-workout-wdelete)
+ - [Viewing workout help: /chelp](#viewing-calories-help-chelp)
+ - [Exit the app: /exit](#exit-the-app-exit)
+- [FAQ](#faq)
+- [Command Summary](#command-summary)
## Introduction
-{Give a product intro}
+Fitz - the ultimate fitness app for individuals who are passionate about their health and fitness.
+With Fitz, you can achieve your fitness goals and track your progress with ease.
+This innovative app is designed for users who prefer a CLI format,
+making it a user-friendly option for anyone who wants to keep their fitness routine on track.
+Whether you're a beginner or an experienced fitness enthusiast, Fitz is the perfect tool for you.
+With its ability to track your daily exercises, workouts, and calories, you can take control of your fitness journey and achieve the results you desire.
+Let's dive into the world of Fitz and discover how it can transform your fitness routine today!
+
## Quick Start
-{Give steps to get started quickly}
+### Setting Up
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+1. Ensure that you have Java 11 or above installed. If not, kindly install Java's [latest version](https://www.oracle.com/java/technologies/downloads/)
+2. Download the latest version of `Fitz` from [here](https://github.com/AY2223S2-CS2113-T14-1).
+3. Copy the file to the folder that you wish to use as a home folder for Fitz.
+The data saved during the application will reside in your /data folder.
+4. Launch a command prompt or terminal and run the command java -jar duke.jar to start the application.
+5. Fitz will display a greeting message.
+6. If you encounter any issues when setting up and hereon, do check out the [FAQ](#faq) section.
-## Features
+## Features
-{Give detailed description of each feature}
+### Start a workout: `/wstart`
+Starts the workout for the current date
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+Format: `/wstart WORKOUT_NAME`
-Format: `todo n/TODO_NAME d/DEADLINE`
+Example of usage:
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+`/wstart chest day`
-Example of usage:
+`/wstart leg day`
+
+Expected output:
+```
+=======================================
+chest day started on 09/04/23.
+=======================================
+```
+
+### Add exercises to current workout: `/wadd`
+Adds exercise to the current workout.
+
+Format: `/wadd EXERCISE_NAME WEIGHT_USED_WEIGHT_UNIT RPS`
+
+* `/wadd` only works after a workout is started with `/wstart`.
+* `WEIGHT_USED_WEIGHT_UNIT` example: 100kg or 100lb (the unit needs to be kg or lb and connected with the weight used)
+* `RPS` needs to be integers separated by a single whitespace
+
+Example of usage:
+
+`/wadd chest press 100kg 7 6 5`
+
+`/wadd leg press 150kg 7 6 5`
+
+Expected output:
+```
+=======================================
+chest press 100kg 7 6 5 has been added.
+=======================================
+```
+
+### List workout dates: `/wlist`
+Display the list of dates of workouts done.
+
+Format: `/wlist`
+
+Example of usage:
+
+`/wlist`
+
+Expected output:
+```
+=======================================
+Here is the list of dates of your workouts:
+1. 08/04/23 chest day
+2. 09/04/23 chest day
+=======================================
+```
+### View a workout: `/wview`
+Display the list of exercises done for a specific workout date.
+
+Format: `/wview INDEX`
+
+* `INDEX` is the number that is displayed when using the `/wlist` function
+* `INDEX` must be on the list.
+*
+Example of usage:
+
+`/wview 3`
+
+Expected output:
+```
+=======================================
+Here are the list of exercises for chest day on 09/04/23.
+1. chest press 100kg 7 6 5
+=======================================
+```
+### Delete a workout: `/wdelete`
+Delete a specified workout based on `INDEX`.
+
+Format: `/wdelete INDEX`
+
+* `INDEX` is the number that is displayed when using the `/wlist` function
+* `INDEX` must be on the list.
+
+Example of usage:
+
+`/wdelete 3`
+
+Expected output:
+```
+=======================================
+Deleted chest day on 09/04/23.
+=======================================
+```
+### End a workout: `/wend`
+End a current workout
+
+Format: `/wend`
+
+Example of usage:
+
+`/wend`
+
+Expected output:
+```
+=======================================
+Great job completing your workout!
+=======================================
+```
+
+### Count sets and reps over a week: `/wcount`
+Displays the list of distinct exercises over a week and the associated total number of sets and reps for each one
+
+Format: `/wcount DD/MM/YY`
+
+* `DD/MM/YY` must be a current or past date, it cannot be a future date.
-`todo n/Write the rest of the User Guide d/next week`
+Example of usage:
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+`/wcount 09/04/23`
+
+Expected output:
+```
+=======================================
+Information of exercises for the week of 09/04/23
+Name: leg press, sets: 3, rps:22
+=======================================
+```
+
+### Viewing Workout Help: `/whelp`
+
+Display basic or detailed help information explaining the commands available in the application.
+
+Format: `/whelp`
+
+Example of usage:
+
+`/whelp`
+
+Expected output:
+```
+Here are the list of commands that you can use for workout record:
+=======================================
+- [Start a workout: /wstart])
+- [Add exercise: /wadd]
+- [Display all the days: /wlist]
+- [Display workouts information for a specific day: /wview]
+- [Display total amount of reps and set for one week /wcount]
+- [Delete workouts: /wdelete]
+- [End current workout: /wend]
+- [Exit app: /exit]
+=======================================
+```
+
+### Add calories consumed: `/cadd`
+Add record of calories consumed.
+
+Format: `/cadd DD/MM/YY FOOD_NAME CALORIE_COUNT`
+
+* `CALORIE_COUNT` can be omitted if food has not been added previously.
+* If user adds food that has been added previously with `CALORIE_COUNT`, the `CALORIE_COUNT` of said food will be updated
+* `DD/MM/YY` must be a current or past date, it cannot be a future date.
+
+Example of usage:
+`/cadd 11/02/23 chicken 100`
+
+Expected output:
+```
+=======================================
+Added chicken(100 kcal) to 11/02/23.
+=======================================
+```
+### List all calorie consumption: `/clist`
+Display the list of dates and total calorie consumption.
+
+Format: `/clist`
+
+Example of usage:
+`/clist`
+
+Expected output:
+```
+=======================================
+Here is your list of daily calorie consumption:
+1. 11/02/23: 100kcal
+=======================================
+```
+
+### View calorie consumption of day: `/cview`
+View the total calorie consumption in a specified date.
+
+Format: `/cview DD/MM/YY`
+
+* `DD/MM/YY` must be a current or past date, it cannot be a future date.
+
+Example of usage:
+`/cview 11/02/23`
+
+Expected output:
+```
+=======================================
+Here are the foods consumed on 11/02/23:
+1. chicken - 100kcal
+=======================================
+```
+
+
+### Viewing Calories Help: `/chelp`
+
+Display basic or detailed help information explaining the commands available in the application.
+
+Format: `/chelp`
+
+Example of usage:
+
+`/chelp`
+
+Expected output:
+```
+Here are the list of commands that you can use for calories record:
+=======================================
+- [Add food and calories: /cadd]
+- [Display total calories consumption: /clist]
+- [Display calories consumed on a specific date : /cview]
+- [Delete calories record for one food: /cdelete]
+- [Exit app: /exit]
+=======================================
+```
+
+### Exit the App: `/exit`
+Exit the program.
+
+Format: `/exit`
+
+Example of usage:
+
+`/exit`
+
+Expected output:
+```
+=======================================
+Thank you, hope you had a great workout!!!
+=======================================
+```
## FAQ
-**Q**: How do I transfer my data to another computer?
+**Q**: Does the app save my workouts when I exit it?
-**A**: {your answer here}
+**A**: As of v2.1, the app does save your data.
## Command Summary
-{Give a 'cheat sheet' of commands here}
-
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+* The list of workout Commands `/whelp`
+* The list of calorie Commands `/chelp`
+* Start a workout `/wstart WORKOUT_NAME`
+* Add exercise `/wadd EXERCISE_NAME WEIGHT_USED_WEIGHT_UNIT RPS`
+* List workout dates: `/wlist`
+* View a workout: `/wview DD/MM/YY`
+* Delete a workout `/wdelete DD/MM/YY`
+* Count sets and reps over a week: `/wcount DD/MM/YY`
+* End current Workout `/wend`
+* Add calories consumed: `/cadd DD/MM/YY FOOD_NAME CALORIES`
+* List calorie consumption dates: `/clist`
+* View calorie consumption: `/cview DD/MM/YY`
+* Delete calorie consumption date: `/cdelete DD/MM/YY`
+* Exit app `/exit`
diff --git a/docs/diagrams/AddExerciseCommandDiagram.puml b/docs/diagrams/AddExerciseCommandDiagram.puml
new file mode 100644
index 0000000000..11351d45d4
--- /dev/null
+++ b/docs/diagrams/AddExerciseCommandDiagram.puml
@@ -0,0 +1,22 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+participant ":AddExerciseCommand" as add
+participant ":WorkoutList" as list
+participant ":Workout" as workout
+
+activate add
+activate list
+activate workout
+-> add: execute()
+add -> list: getCurrentWorkoutIndex()
+list -> add: currentWorkoutIndex
+alt no current workout
+<- add: no current workout message
+else
+add -> list: getCurrentWorkout()
+list -> workout: addExercise(toAdd)
+<- add: add exercise message
+end
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml
new file mode 100644
index 0000000000..f213f4ea79
--- /dev/null
+++ b/docs/diagrams/ArchitectureDiagram.puml
@@ -0,0 +1,38 @@
+@startuml
+hide footbox
+hide circle
+skinparam classAttributeIconSize 0
+!include Style.puml
+
+Package "FITZ"<>{
+ class Ui
+ class Storage
+ class Parser
+ class Exception
+ class Command
+ class Duke
+ class Calories
+ class Workout
+}
+
+User .right.> Ui
+
+
+Duke -left-> Storage
+Duke --> Parser
+Duke -up-> Ui
+Duke -up-> Exception
+
+Parser --> Command
+
+Command -left-> Ui
+Exception -up> Ui
+
+Storage -up-> Calories
+Storage -right-> Workout
+
+Storage --> Ui
+
+Storage .left.> File
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
new file mode 100644
index 0000000000..185f650ab0
--- /dev/null
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -0,0 +1,56 @@
+@startuml
+hide footbox
+!include Style.puml
+
+Actor User
+activate ":Duke"
+":Duke" -> ":Ui" : showWelcomeMessage()
+activate ":Ui"
+":Ui" --> ":Duke"
+deactivate ":Ui"
+":Duke" -> ":Storage" : new
+activate ":Storage"
+return
+deactivate ":Storage"
+
+
+
+loop until isExit()
+ ":Duke" -> ":Duke": Parser()
+ activate ":Duke"
+ ":Duke" -> ":Ui": getUserInput()
+ activate ":Ui"
+ User -> ":Ui":input
+ return
+ ":Duke" -> ":Parser" : processCommand()
+ activate ":Parser"
+ ":Parser" -> ":Matcher"** : group()
+ activate ":Matcher"
+ return
+ ":Parser" --> ":Parser"
+ deactivate ":Parser"
+
+
+ alt command is valid
+ ":Duke" -> ":Ui" : showCommandResult()
+ activate ":Ui"
+ return
+ deactivate ":Duke"
+
+ else command is invalid
+ ":Duke" -> ":Ui" : showErrorMessage()
+ activate ":Ui"
+ ":Ui" -> ":Exception" : toString()
+ activate ":Exception"
+ return
+ destroy ":Exception"
+ return
+ destroy ":Ui"
+ ":Duke" -> ":Command"**: new
+ activate ":Command"
+ return
+ end
+end
+deactivate ":Duke"
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/CaloriesAddDiagram.puml b/docs/diagrams/CaloriesAddDiagram.puml
new file mode 100644
index 0000000000..5836199106
--- /dev/null
+++ b/docs/diagrams/CaloriesAddDiagram.puml
@@ -0,0 +1,16 @@
+@startuml
+
+!include Style.puml
+
+actor User
+participant AddCalorieCommand
+participant CalorieTracker
+participant FoodList
+
+User -> AddCalorieCommand: execute(date, foodName, foodCalories)
+AddCalorieCommand -> CalorieTracker: addCalories(date, foodName, foodCalories)
+CalorieTracker -> FoodList: addFood(foodName, foodCalories)
+FoodList -> CalorieTracker: updateTotalCalories(date)
+CalorieTracker -> AddCalorieCommand: return result
+AddCalorieCommand -> User: return result
+@enduml
diff --git a/docs/diagrams/CaloriesComponentClassDiagram.puml b/docs/diagrams/CaloriesComponentClassDiagram.puml
new file mode 100644
index 0000000000..f34721836d
--- /dev/null
+++ b/docs/diagrams/CaloriesComponentClassDiagram.puml
@@ -0,0 +1,70 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+ class CalorieTracker {
+ - dailyFoodConsumption: HashMap
+ - foodDictionary: FoodDictionary
+ + CalorieTracker(Storage, FoodDictionary)
+ + getFoodList(Date): FoodList
+ + getDailyFoodConsumption(): HashMap
+ + addCalories(Date, String, int): String
+ }
+
+ class Food{
+ - foodName: String
+ - calories: int
+ + Food(String, int)
+ + getFoodName(): String
+ + getCalories(): int
+
+ }
+
+ class FoodDictionary{
+ - foodCalories: HashMap
+ + FoodDictionary(Storage)
+ + addFood(String, int): void
+ + contains(String): boolean
+ + getFoodCalories(): HashMap
+
+ }
+ class FoodList{
+ - foods: ArrayList
+ - totalCalories: int
+ + FoodList()
+ + addFood(Food): void
+ + getFoods(): ArrayList
+ + getFood(int): Food
+ + getTotalCalories(): int
+ + deleteFood(int): void
+
+}
+
+ class FoodDictionaryStorage{
+ {static} - defaultFoodDictionaryFile: File
+ - foodDictionaryFile: File
+ - readFoodDictionaryFileLine(String, HashMap): void
+ - createFoodDictionaryFile(): void
+ + saveUserData(HashMap): void
+ + FoodDictionaryStorage()
+ }
+
+
+ class CaloriesTrackerStorage{
+ {static} - defaultCalorieTrackerFile: File
+ + calorieTrackerFile: File
+ + CalorieTrackerStorage()
+ + getUserData(): HashMap
+ + readCalorieTrackerFile(String, HashMap): void
+ + createCalorieTrackerFile(): void
+ + saveUserData(HashMap): void
+ }
+
+FoodList *--> "0..*" Food: list of food
+CalorieTracker *--> "0..*" FoodList: list of food for one day
+FoodDictionaryStorage -[dashed]-> FoodDictionary: > loads and write data
+CalorieTracker -[dashed]-> FoodDictionary: > check the food information
+CaloriesTrackerStorage -[dashed]-> CalorieTracker: > loads and write data
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/CommandArchitectureDiagram.puml b/docs/diagrams/CommandArchitectureDiagram.puml
new file mode 100644
index 0000000000..e7614e6c1b
--- /dev/null
+++ b/docs/diagrams/CommandArchitectureDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include Style.puml
+
+Package "commands"<>{
+ class Command
+ class ExitCommand
+
+Package "workoutcommands"<>{
+ class AddExerciseCommand
+ class CountSetsRepsCommand
+ class DeleteWorkoutCommand
+ class EndWorkoutCommand
+ class HelpWorkoutCommand
+ class ListWorkoutCommand
+ class StartWorkoutCommand
+ class ViewWorkoutCommand
+}
+Package "caloriescommands"<>{
+ class AddCaloriesCommand
+ class DeleteCaloriesCommand
+ class HelpCaloriesCommand
+ class ListCaloriesCommand
+ class ViewCaloriesCommand
+}
+Package "errorcommands"<>{
+ class IncorrectSyntaxCommand
+ class InvalidCommand
+}
+
+}
+
+Command <|-up- "errorcommands"
+Command <|-down- "workoutcommands"
+Command <|-up- "caloriescommands"
+Command <|-down- "ExitCommand"
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/CommandComponentClassDiagram.puml b/docs/diagrams/CommandComponentClassDiagram.puml
new file mode 100644
index 0000000000..c597dfa0b5
--- /dev/null
+++ b/docs/diagrams/CommandComponentClassDiagram.puml
@@ -0,0 +1,152 @@
+@startuml
+!include Style.puml
+
+Package "commands"<>{
+
+ class Command {
+ # workoutList: WorkoutList
+ # calorieTracker: CalorieTracker
+ # foodDictionary: FoodDictionary
+ + setDate(WorkoutList, CalorieTracker, FoodDictionary): void
+ + execute(): String
+ }
+
+ class ExitCommand {
+ {static} - EXIT_MESSAGE : String
+ {static} + isExit(Command): boolean
+ + execute(): String
+}
+Package "workoutcommands"<>{
+
+ class AddExerciseCommand{
+ {static} - EXERCISE_ADDED_MESSAGE: String
+ {static} - NO_CURRENT_WORKOUT_MESSAGE: String
+ - exerciseToAdd: Exercise
+ + AddExerciseCommand(Exercise)
+ + execute(): String
+ }
+
+ class CountSetsRepsCommand{
+ - dayInSpecificWeekDate: Date
+ + CountSetsRepsCommand(Date)
+ + execute(): String
+ }
+
+ class DeleteWorkoutCommand{
+ - workoutToDeleteIndex: int
+ + DeleteWorkoutCommand(int)
+ + execute(): String
+ }
+
+ class EndWorkoutCommand{
+ {static} - NO_CURRENT_WORKOUT_MESSAGE: String
+ {static} - WORKOUT_COMPLETE_MESSAGE: String
+ + EndWorkoutCommand()
+ + execute(): String
+ }
+
+ class HelpWorkoutCommand{
+ + HelpWorkoutCommand()
+ + execute(): String
+ }
+
+ class ListWorkoutCommand{
+ {static} - EMPTY_LIST_MESSAGE: String
+ {static} - WORKOUT_LIST_HEADER: String
+ + ListWorkoutCommand()
+ + execute(): String
+ }
+
+ class StartWorkoutCommand{
+ {static} - ONGOING_WORKOUT_MESSAGE: String
+ - workoutName: String
+ - date: Date
+ + StartWorkoutCommand(Date)
+ + execute(): String
+ }
+
+ class ViewWorkoutCommand{
+ - workoutToViewIndex: int
+ + ViewWorkoutCommand(int)
+ + execute(): String
+ }
+
+}
+Package "caloriescommands"<>{
+
+ class AddCaloriesCommand{
+ {static} - CALORIES_NOT_GIVEN: int
+ - date: Date
+ - foodName: String
+ - foodCalories: int
+ + AddCalorieCommand(Date, String, int)
+ + AddCalorieCommand(Date, String)
+ + execute(): String
+ }
+
+ class DeleteCaloriesCommand{
+ {static} + NO_INDEX: int
+ - date: Date
+ - index: int
+ + DeleteCalorieCommand(Date)
+ + DeleteCalorieCommand(Date, int)
+ + execute(): String
+ }
+
+ class HelpCaloriesCommand{
+ + execute(): String
+}
+
+ class ListCaloriesCommand{
+ {static} - EMPTY_LIST_MESSAGE: String
+ {static} - HEADER: String
+ + ListCaloriesCommand()
+ + execute(): String
+ }
+
+ class ViewCaloriesCommand{
+ {static} - HEADER: String
+ {static} - FAIL_TO_FIND_DATE: String
+ - caloriesToViewDate: Date
+ + ViewCaloriesCommand(Date)
+ + execute(): String
+ }
+
+}
+Package "errorcommands"<>{
+ class IncorrectSyntaxCommand{
+ {static} - ERROR_MESSAGE: String
+ - syntaxError: String
+ + IncorrectSyntaxCommand(String)
+ + execute(): String
+ }
+
+ class InvalidCommand{
+ {static} - INVALID_COMMAND_MESSAGE: String
+ - command: String
+ + InvalidCommand(String)
+ + execute(): String
+ }
+}
+
+
+}
+
+Command <|-- "AddExerciseCommand": inherits from
+Command <|-- "CountSetsRepsCommand": inherits from
+Command <|-- "DeleteWorkoutCommand": inherits from
+Command <|-- "EndWorkoutCommand": inherits from
+Command <|-up- "HelpWorkoutCommand": inherits from
+Command <|-- "ListWorkoutCommand": inherits from
+Command <|-- "StartWorkoutCommand": inherits from
+Command <|-- "ViewWorkoutCommand": inherits from
+Command <|-up- "AddCaloriesCommand": inherits from
+Command <|-up- "DeleteCaloriesCommand": inherits from
+Command <|-up- "HelpCaloriesCommand": inherits from
+Command <|-up- "ListCaloriesCommand": inherits from
+Command <|-up- "ViewCaloriesCommand": inherits from
+Command <|-right- "IncorrectSyntaxCommand": inherits from
+Command <|-right- "InvalidCommand": inherits from
+Command <|-left- "ExitCommand": inherits from
+
+@endumlml
\ No newline at end of file
diff --git a/docs/diagrams/CountSetsRepsDiagram.puml b/docs/diagrams/CountSetsRepsDiagram.puml
new file mode 100644
index 0000000000..8ddb000471
--- /dev/null
+++ b/docs/diagrams/CountSetsRepsDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include Style.puml
+
+autonumber
+actor User
+participant Duke
+participant Ui
+participant Parser
+participant WorkoutParser
+participant CountSetsRepsCommand
+participant WorkoutList
+
+Duke -> Ui: getUserInput()
+activate Duke
+activate Ui
+User -> Ui: User input
+return User input
+Duke -> Parser : processCommand(userInput)
+activate Parser
+Parser -> WorkoutParser : parseSetsRepsCountCommand(arguments)
+activate WorkoutParser
+WorkoutParser -> CountSetsRepsCommand : countSetsRepsCommand(date)
+activate CountSetsRepsCommand
+CountSetsRepsCommand -> WorkoutList : countSetsReps(dayInSpecificWeekDate)
+activate WorkoutList
+WorkoutList -> WorkoutList : displayCountSetsReps \n(distinctExercises,dayInSpecificWeekDate)
+return output
+deactivate WorkoutList
+CountSetsRepsCommand --> WorkoutParser : output
+deactivate CountSetsRepsCommand
+WorkoutParser --> Parser : output
+deactivate WorkoutParser
+Parser --> Duke : output
+deactivate Parser
+Duke -> Duke : display(output)
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/DeleteLCalorieDiagram.puml b/docs/diagrams/DeleteLCalorieDiagram.puml
new file mode 100644
index 0000000000..d3f87b8b52
--- /dev/null
+++ b/docs/diagrams/DeleteLCalorieDiagram.puml
@@ -0,0 +1,20 @@
+@startuml
+!include Style.puml
+'https://plantuml.com/sequence-diagram
+actor User
+participant DeleteCalorieCommand
+participant calorieTracker
+participant DailyFoodConsumption
+participant Food
+participant DateFormatter
+
+User -> DeleteCalorieCommand: deleteCalorie(date)
+DeleteCalorieCommand -> calorieTracker: getDailyFoodConsumption()
+calorieTracker -> DailyFoodConsumption: get(date)
+DeleteCalorieCommand -> DailyFoodConsumption: deleteFood(index)
+DailyFoodConsumption -> Food: getFood(index)
+Food -> DeleteCalorieCommand: deletedFood
+DeleteCalorieCommand -> DateFormatter: dateToString(date)
+DeleteCalorieCommand -> User: "Deleted (foodName) (calories) from (date)"
+
+@enduml
diff --git a/docs/diagrams/DeleteWorkoutDiagram.puml b/docs/diagrams/DeleteWorkoutDiagram.puml
new file mode 100644
index 0000000000..4cdf5e7c8b
--- /dev/null
+++ b/docs/diagrams/DeleteWorkoutDiagram.puml
@@ -0,0 +1,35 @@
+@startuml
+!include Style.puml
+
+autonumber
+actor User
+participant Duke
+participant Ui
+participant Parser
+participant WorkoutParser
+participant DeleteWorkoutCommand
+participant WorkoutList
+
+Duke -> Ui: getUserInput()
+activate Duke
+activate Ui
+User -> Ui: User input
+return User input
+Duke -> Parser : processCommand(userInput)
+activate Parser
+Parser -> WorkoutParser : parseDeleteWorkoutCommand(arguments)
+activate WorkoutParser
+WorkoutParser -> DeleteWorkoutCommand : DeleteWorkoutCommand(index)
+activate DeleteWorkoutCommand
+DeleteWorkoutCommand -> WorkoutList : remove(index)
+activate WorkoutList
+return "Workout deleted"
+deactivate WorkoutList
+DeleteWorkoutCommand --> WorkoutParser : "Workout deleted"
+deactivate DeleteWorkoutCommand
+WorkoutParser --> Parser : "Workout deleted"
+deactivate WorkoutParser
+Parser --> Duke : "Workout deleted"
+deactivate Parser
+Duke -> Duke : display("Workout deleted")
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/EndWorkoutCommandDiagram.puml b/docs/diagrams/EndWorkoutCommandDiagram.puml
new file mode 100644
index 0000000000..b8599fbd2e
--- /dev/null
+++ b/docs/diagrams/EndWorkoutCommandDiagram.puml
@@ -0,0 +1,19 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+participant ":EndWorkoutCommand" as end
+participant ":WorkoutList" as list
+
+activate end
+activate list
+-> end: execute()
+end -> list: getCurrentWorkoutIndex()
+list -> end: currentWorkoutIndex
+alt no current workout
+<- end: no ongoing workout message
+else
+end -> list: setCurrentWorkoutIndex(NO_CURRENT_WORKOUT)
+<- end: end workout message
+end
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ExitCommandDiagram.puml b/docs/diagrams/ExitCommandDiagram.puml
new file mode 100644
index 0000000000..b0fc24c42d
--- /dev/null
+++ b/docs/diagrams/ExitCommandDiagram.puml
@@ -0,0 +1,18 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+actor user
+participant ":Duke" as duke
+participant ":Parser" as parser
+
+activate duke
+activate parser
+duke -> duke: executeCommandUntilExit()
+loop until exit
+duke -> user: getUserInput()
+user -> duke: userInput
+duke -> parser: parseCommand(userInput)
+parser -> duke: command
+end
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ListCalorieDiagram.puml b/docs/diagrams/ListCalorieDiagram.puml
new file mode 100644
index 0000000000..7700d7a940
--- /dev/null
+++ b/docs/diagrams/ListCalorieDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include Style.puml
+
+actor User
+
+User -> ListCaloriesCommand: execute()
+activate ListCaloriesCommand
+
+ListCaloriesCommand -> calorieTracker: getDailyFoodConsumption()
+activate calorieTracker
+calorieTracker -> TreeMap: TreeMap()
+activate TreeMap
+calorieTracker <-- TreeMap: sortedMap
+deactivate TreeMap
+deactivate calorieTracker
+
+alt list is empty
+ ListCaloriesCommand --> User: "Calorie consumption list is empty!"
+end
+ ListCaloriesCommand -> TreeMap: keySet()
+ activate TreeMap
+
+ loop through daily food consumption
+ TreeMap -> FoodList: getTotalCalories()
+ activate FoodList
+ TreeMap <-- FoodList: totalCalories
+ FoodList <-- TreeMap
+ TreeMap --> ListCaloriesCommand: display data
+ deactivate FoodList
+ end
+
+
+ ListCaloriesCommand --> User: display data
+
+deactivate ListCaloriesCommand
+@enduml
diff --git a/docs/diagrams/ListWorkoutDiagram.puml b/docs/diagrams/ListWorkoutDiagram.puml
new file mode 100644
index 0000000000..d536c1e1cd
--- /dev/null
+++ b/docs/diagrams/ListWorkoutDiagram.puml
@@ -0,0 +1,71 @@
+
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+autonumber
+actor User
+participant ":Duke" as Duke
+participant ":Ui" as Ui
+participant ":Parser" as Parser
+participant ":CheckInput" as CheckInputs
+participant ":ListWorkoutCommand" as ListWorkoutCommand
+participant ":WorkoutList" as WorkoutList
+
+
+Duke -> Ui: getUserInput()
+activate Duke
+activate Ui
+User -> Ui: User input
+return User input
+Duke -> Parser : processCommand(userInput)
+activate Parser
+Parser -> CheckInputs : processList(arguments)
+activate CheckInputs
+CheckInputs -> ListWorkoutCommand : ListWorkoutCommand(date)
+activate ListWorkoutCommand
+ListWorkoutCommand -> WorkoutList : getWorkoutArrayList()
+activate WorkoutList
+return workoutArrayList
+ListWorkoutCommand --> CheckInputs : LINE_SEPARATOR
+deactivate ListWorkoutCommand
+CheckInputs --> Parser : LINE_SEPARATOR
+deactivate CheckInputs
+Parser --> Duke : LINE_SEPARATOR
+Duke -> Duke : display(LINE_SEPARATOR)
+
+@startuml
+'https://plantuml.com/sequence-diagram
+
+autonumber
+actor User
+participant ":Duke" as Duke
+participant ":Ui" as Ui
+participant ":Parser" as Parser
+participant ":CheckInput" as CheckInputs
+participant ":ListWorkoutCommand" as ListWorkoutCommand
+participant ":WorkoutList" as WorkoutList
+
+
+Duke -> Ui: getUserInput()
+activate Duke
+activate Ui
+User -> Ui: User input
+return User input
+Duke -> Parser : processCommand(userInput)
+activate Parser
+Parser -> CheckInputs : processList(arguments)
+activate CheckInputs
+CheckInputs -> ListWorkoutCommand : ListWorkoutCommand(date)
+activate ListWorkoutCommand
+ListWorkoutCommand -> WorkoutList : getWorkoutArrayList()
+activate WorkoutList
+return workoutArrayList
+ListWorkoutCommand --> CheckInputs : LINE_SEPARATOR
+deactivate ListWorkoutCommand
+CheckInputs --> Parser : LINE_SEPARATOR
+deactivate CheckInputs
+Parser --> Duke : LINE_SEPARATOR
+Duke -> Duke : display(LINE_SEPARATOR)
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/StartWorkoutCommandDiagram.puml b/docs/diagrams/StartWorkoutCommandDiagram.puml
new file mode 100644
index 0000000000..0406817226
--- /dev/null
+++ b/docs/diagrams/StartWorkoutCommandDiagram.puml
@@ -0,0 +1,24 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+participant ":StartWorkoutCommand" as start
+participant ":WorkoutList" as list
+participant ":Workout" as workout
+
+activate start
+activate list
+-> start: execute()
+start -> list: getCurrentWorkoutIndex()
+list -> start: currentWorkoutIndex
+alt ongoing workout
+<- start: end workout first message
+else
+start -> list: startWorkout(date, workoutName)
+list -> workout: Workout(date, workoutName)
+activate workout
+workout -> list: workout
+list -> list: add(workout)
+<- start: start workout message
+end
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/StorageComponentDiagram.puml b/docs/diagrams/StorageComponentDiagram.puml
new file mode 100644
index 0000000000..752e4d8b41
--- /dev/null
+++ b/docs/diagrams/StorageComponentDiagram.puml
@@ -0,0 +1,47 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+ class Storage {
+ - workoutListStorage: WorkoutListStorage
+ - foodDictionaryStorage: FoodDictionaryStorage
+ - calorieTrackerStorage: CalorieTrackerStorage
+ + Storage()
+ + readWorkoutListFile(): ArrayList
+ + readFoodDictionaryFile(): HashMap
+ + readCalorieTrackerFile(): HashMap
+ + saveUserData(WorkoutList, FoodDictionary, CalorieTracker): void
+ }
+
+ class CaloriesTrackerStorage{
+ {static} - defaultCalorieTrackerFile: File
+ + calorieTrackerFile: File
+ + CalorieTrackerStorage()
+ + getUserData(): HashMap
+ + readCalorieTrackerFile(String, HashMap): void
+ + createCalorieTrackerFile(): void
+ + saveUserData(HashMap): void
+ }
+ class FoodDictionaryStorage{
+ {static} - defaultFoodDictionaryFile: File
+ - foodDictionaryFile: File
+ - readFoodDictionaryFileLine(String, HashMap): void
+ - createFoodDictionaryFile(): void
+ + saveUserData(HashMap): void
+ + FoodDictionaryStorage()
+ }
+ class WorkoutListStorage{
+ {static} - defaultWorkoutListFile: File
+ - workoutListFile: File
+ - readWorkoutListFileLine(String, ArrayList): void
+ - createWorkoutListFile(): void
+ + WorkoutListStorage()
+ + getUserData(): ArrayList
+ + saveUserData(ArrayList workouts): void
+ }
+
+Storage --> "1" WorkoutListStorage: workoutListFile
+Storage --> "1" FoodDictionaryStorage: foodDictionaryStorage
+Storage --> "1" CaloriesTrackerStorage: caloriesTrackerStorage
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Style.puml b/docs/diagrams/Style.puml
new file mode 100644
index 0000000000..6b48195383
--- /dev/null
+++ b/docs/diagrams/Style.puml
@@ -0,0 +1,267 @@
+''
+'' Cyborg theme based off of the bootstrap theme of the same name, with outline colors
+'' https://bootswatch.com/cyborg/
+''
+'' Author: Brett Schwarz
+'' Copyright (c) 2019 by Brett Schwarz
+
+!$THEME = "cyborg-outline"
+
+hide circle
+skinparam classAttributeIconSize 0
+hide footbox
+
+!if %not(%variable_exists("$BGCOLOR"))
+!$BGCOLOR = "white"
+!endif
+
+skinparam backgroundColor $BGCOLOR
+skinparam useBetaStyle false
+
+''
+'' Colors taken from the css file of the BS theme
+''
+!$BLACK = "#000000"
+!$BLUE = "#2A9FD6"
+!$INDIGO = "#6610f2"
+!$PURPLE = "#6f42c1"
+!$PINK = "#e83e8c"
+!$RED = "#CC0000"
+!$ORANGE = "#fd7e14"
+!$YELLOW = "#FF8800"
+!$GREEN = "#77B300"
+!$TEAL = "#20c997"
+!$CYAN = "#9933CC"
+!$WHITE = "#FFF"
+!$GRAY_LIGHT = "#222"
+!$GRAY = "#555"
+!$PRIMARY = "#2A9FD6"
+!$SECONDARY = "#555"
+!$SUCCESS = "#77B300"
+!$INFO = "#9933CC"
+!$WARNING = "#FF8800"
+!$DANGER = "#CC0000"
+!$LIGHT = "#222"
+!$DARK = "#ADAFAE"
+
+'' *_DARK = tint (lighter) of the main color of 80%
+'' where TINT is calculated by clr + (255-clr) * tint_factor
+'' *_LIGHT = shade (darker) of the main color of 80%
+'' and SHADE is calculated by clr * (1 - shade_factor)
+''
+!$FGCOLOR = $BLACK
+!$PRIMARY_DARK = "#55B2DE"
+!$PRIMARY_LIGHT = "#227FAB"
+!$PRIMARY_TEXT = $PRIMARY
+!$SECONDARY_DARK = "#777777"
+!$SECONDARY_LIGHT = "#444444"
+!$SECONDARY_TEXT = $SECONDARY_DARK
+!$INFO_DARK = "#00008B"
+!$INFO_LIGHT = "#7a29a3"
+!$INFO_TEXT = $INFO
+!$SUCCESS_DARK = "#92C233"
+!$SUCCESS_LIGHT = "#5F8F00"
+!$SUCCESS_TEXT = $SUCCESS
+!$WARNING_DARK = "#FFA033"
+!$WARNING_LIGHT = "#cc6d00"
+!$WARNING_TEXT = $WARNING
+!$DANGER_DARK = "#D63333"
+!$DANGER_LIGHT = "#a30000"
+!$DANGER_TEXT = $WHITE
+!$DARK_DARK = "#BDBFBE"
+!$DARK_LIGHT = "#8A8C8B"
+!$LIGHT_DARK = "#4E4E4E"
+!$LIGHT_LIGHT = "#1B1B1B"
+
+!procedure $success($msg)
+ $msg
+!endprocedure
+
+!procedure $failure($msg)
+ $msg
+!endprocedure
+
+!procedure $warning($msg)
+ $msg
+!endprocedure
+
+!procedure $primary_scheme()
+ FontColor $PRIMARY_TEXT
+ BorderColor $PRIMARY_DARK
+ BackgroundColor $BGCOLOR
+!endprocedure
+
+''
+'' Global Default Values
+''
+skinparam defaultFontName "Verdana"
+skinparam defaultFontSize 12
+skinparam dpi 300
+' Set to 100 when you want to save the diagram
+skinparam shadowing false
+skinparam roundcorner 8
+skinparam ParticipantPadding 0
+skinparam BoxPadding 40
+skinparam Padding 4
+skinparam ArrowColor $DARK
+skinparam stereotype {
+ CBackgroundColor $SECONDARY_DARK
+ CBorderColor $SECONDARY_LIGHT
+ ABackgroundColor $SUCCESS_LIGHT
+ ABorderColor $SUCCESS_DARK
+ IBackgroundColor $DANGER_LIGHT
+ IBorderColor $DANGER_DARK
+ EBackgroundColor $WARNING_LIGHT
+ EBorderColor $WARNING_DARK
+ NBackgroundColor $INFO_LIGHT
+ NBorderColor $INFO_DARK
+}
+skinparam title {
+ FontColor $PRIMARY
+ BorderColor $SECONDARY_DARK
+ FontSize 20
+ BorderRoundCorner 8
+ BorderThickness 1
+ BackgroundColor $BGCOLOR
+}
+
+skinparam legend {
+ BackgroundColor $BGCOLOR
+ BorderColor $SECONDARY_DARK
+ FontColor $DARK
+}
+
+!startsub participant
+
+skinparam participant {
+ $primary_scheme()
+ ParticipantBorderThickness 2
+}
+!endsub
+
+!startsub actor
+
+skinparam actor {
+ $primary_scheme()
+ FontColor $PRIMARY
+}
+!endsub
+
+!startsub arrow
+
+skinparam arrow {
+ Thickness 1
+ Color $PRIMARY
+ FontColor $FGCOLOR
+}
+!endsub
+
+!startsub sequence
+
+skinparam sequence {
+ BorderColor $PRIMARY
+ ' For some reason sequence title font color does not pick up from global
+ TitleFontColor $PRIMARY
+ BackgroundColor $BGCOLOR
+ StartColor $PRIMARY
+ EndColor $PRIMARY
+ ''
+ BoxBackgroundColor $BGCOLOR
+ BoxBorderColor $DARK
+ BoxFontColor $DARK
+ ''
+ DelayFontColor $DARK
+ ''
+ LifeLineBorderColor $SECONDARY
+ LifeLineBorderThickness 2
+ LifeLineBackgroundColor $WHITE
+ ''
+ GroupBorderColor $DARK
+ GroupFontColor $DARK
+ GroupHeaderFontColor $BLACK
+ GroupBackgroundColor $BGCOLOR
+ GroupBodyBackgroundColor $BGCOLOR
+ GroupHeaderBackgroundColor $BGCOLOR
+ ''
+ DividerBackgroundColor $BGCOLOR
+ DividerBorderColor $DARK
+ DividerBorderThickness 2
+ DividerFontColor $DARK
+ ''
+ ReferenceBackgroundColor $BGCOLOR
+ ReferenceBorderColor $DARK
+ ReferenceFontColor $DARK
+ ReferenceHeaderFontColor $INFO_TEXT
+ ReferenceHeaderBackgroundColor $BGCOLOR
+ ''
+ StereotypeFontColor $PRIMARY_TEXT
+}
+!endsub
+
+!startsub note
+
+skinparam note {
+ BorderThickness 1
+ BackgroundColor $BGCOLOR
+ BorderColor $INFO_DARK
+ FontColor $INFO_DARK
+}
+!endsub
+
+!startsub component
+
+skinparam component {
+ $primary_scheme()
+}
+!endsub
+
+!startsub interface
+
+skinparam interface {
+ BackgroundColor $BGCOLOR
+ BorderColor $DANGER
+ FontColor $DARK
+}
+!endsub
+
+!startsub class
+
+skinparam class {
+ $primary_scheme()
+ FontColor $LIGHT
+ HeaderBackgroundColor $TRANSPARENT
+ StereotypeFontColor $DARK
+ BorderThickness 1
+ AttributeFontColor $BLACK
+ AttributeFontSize 11
+}
+!endsub
+
+!startsub rectangle
+
+skinparam rectangle {
+ $primary_scheme()
+ BorderThickness 2
+ StereotypeFontColor $PRIMARY
+}
+!endsub
+
+!startsub package
+
+skinparam package {
+ BackgroundColor $BGCOLOR
+ BorderColor $PRIMARY
+ FontColor $PRIMARY
+ BorderThickness 2
+}
+!endsub
+
+!startsub frame
+
+skinparam frame {
+ BackgroundColor $BGCOLOR
+ BorderColor $INFO
+ FontColor $INFO_TEXT
+ BorderThickness 2
+}
+!endsub
\ No newline at end of file
diff --git a/docs/diagrams/UiComponentClassDiagram.puml b/docs/diagrams/UiComponentClassDiagram.puml
new file mode 100644
index 0000000000..2d441081fc
--- /dev/null
+++ b/docs/diagrams/UiComponentClassDiagram.puml
@@ -0,0 +1,26 @@
+@startuml
+skinparam classAttributeIconSize 0
+hide footbox
+hide circle
+!include Style.puml
+
+class Ui{
+ + {static} line(): String
+ + {static} getUserInput(): String
+ + {static} getWorkoutHelpMessage(): String
+ + {static} getCaloriesHelpMessage(): String
+ + {static} showGreeting(): void
+ + {static} showLogo(): void
+ + {static} showOneLine(): void
+ + {static} showWelcomeMessage(): void
+ + {static} showErrorMessage(): void
+ + {static} showCommandResult(): void
+ + {static} showReadFileErrorMessage(): void
+ + {static} showCreatedNewFileMessage(): void
+ + {static} showNewFileNotCreatedMessage(): void
+ + {static} showCreateDirectoryMessage(): void
+ + {static} showDirectoryNotCreatedMessage(): void
+ + {static} showSaveUserDataErrorMessage(): void
+ + {static} showSuccessfulLoadDataMessage(): void
+}
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ViewCalorieDiagram.puml b/docs/diagrams/ViewCalorieDiagram.puml
new file mode 100644
index 0000000000..8f68637237
--- /dev/null
+++ b/docs/diagrams/ViewCalorieDiagram.puml
@@ -0,0 +1,26 @@
+@startuml
+!include Style.puml
+actor User
+participant "ViewCaloriesCommand" as VCC
+participant "calorieTracker" as CT
+database "Daily Food Consumption" as DFC
+participant "Food" as F
+participant "DateFormatter" as DF
+participant "Ui" as UI
+
+User -> VCC : Requests to view calories for a specific date
+VCC -> CT : Checks if date exists in daily food consumption
+CT -> DFC : Retrieves daily food consumption for the date
+DFC -> VCC : Returns daily food consumption
+alt Date exists in daily food consumption
+ VCC -> DF : Formats the date
+ VCC -> F : Retrieves food list from daily food consumption
+ loop for each food in the list
+ VCC -> F : Retrieves food name and calories
+ VCC -> UI : Formats and displays the food name and calories
+ end
+else Date does not exist in daily food consumption
+ VCC -> DF : Formats the date
+ VCC -> UI : Returns a message that the date does not exist in the list
+end
+@enduml
diff --git a/docs/diagrams/ViewDiagram.puml b/docs/diagrams/ViewDiagram.puml
new file mode 100644
index 0000000000..165e4d26f2
--- /dev/null
+++ b/docs/diagrams/ViewDiagram.puml
@@ -0,0 +1,19 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+autonumber
+actor User
+participant ":Duke" as Duke
+
+User -> Duke: Userinput
+activate Duke
+Duke -> Parser : parseViewWorkoutCommand(arguments)
+activate Parser
+Parser-> WorkoutParser: processView(arguments)
+activate WorkoutParser
+WorkoutParser->ViewWorkoutCommand : ViewWorkoutCommand(index)
+activate ViewWorkoutCommand
+return toView.toString()
+return toView.toString()
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/WorkoutComponentClassDiagram.puml b/docs/diagrams/WorkoutComponentClassDiagram.puml
new file mode 100644
index 0000000000..7d0c564342
--- /dev/null
+++ b/docs/diagrams/WorkoutComponentClassDiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include Style.puml
+
+ class Exercise{
+ - name: String
+ - weight: String
+ - repsPerSet: String
+ - Exercise(String, String, String)
+ + getName(): String
+ + getWeight(): String
+ + getRepsPerSet(): String
+ + toString(): toString
+ + getSetsCount(): int
+ + getRepsCount(): int
+ }
+
+ class Workout{
+ - date: Date
+ - workoutName: String
+ - exercises: ArrayList
+ + Workout()
+ + Workout(Date, String)
+ + getWorkoutName(): String
+ + getDate(): Date
+ + getExercises(): ArrayList
+ + addExercise(Exercise): void
+ + toString(): String
+ }
+
+ class WorkoutList{
+ {static} - EMPTY_WORKOUT: String
+ {static} - INFORMATION: String
+ {static} - NO_CURRENT_WORKOUT: int
+ - workouts: ArrayList
+ - currentWorkoutIndex: int
+ - isInlist(Workout): boolean
+ + WorkoutList()
+ + WorkoutList(Storage)
+ + getCurrentWorkoutIndex(): int
+ + getWorkouts(): ArrayList
+ + countSetsReps(Date): String
+ + displayCountSetsReps(HashMap>, Date): String
+ + getWorkoutsInSpecificWeek: ArrayList
+ + startWorkout(Date, String)
+ + isEmptyList(): boolean
+ + getWorkout(int): Workout
+ + getCurrentWorkout(): Workout
+ }
+
+ Workout *--> "0..*" Exercise: list of exercises
+ WorkoutList *--> "0..*" Workout: list of workouts
+@enduml
\ No newline at end of file
diff --git a/docs/images/AddExerciseCommandDiagram.png b/docs/images/AddExerciseCommandDiagram.png
new file mode 100644
index 0000000000..13d86b20f2
Binary files /dev/null and b/docs/images/AddExerciseCommandDiagram.png differ
diff --git a/docs/images/ArchitectureDiagram.png b/docs/images/ArchitectureDiagram.png
new file mode 100644
index 0000000000..28841a61c9
Binary files /dev/null and b/docs/images/ArchitectureDiagram.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
new file mode 100644
index 0000000000..f3213091d9
Binary files /dev/null and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/CaloriesAddDiagram.png b/docs/images/CaloriesAddDiagram.png
new file mode 100644
index 0000000000..da01872388
Binary files /dev/null and b/docs/images/CaloriesAddDiagram.png differ
diff --git a/docs/images/CaloriesComponentClassDiagram.png b/docs/images/CaloriesComponentClassDiagram.png
new file mode 100644
index 0000000000..0b33cae956
Binary files /dev/null and b/docs/images/CaloriesComponentClassDiagram.png differ
diff --git a/docs/images/CommandArchitectureDiagram.png b/docs/images/CommandArchitectureDiagram.png
new file mode 100644
index 0000000000..888fd58384
Binary files /dev/null and b/docs/images/CommandArchitectureDiagram.png differ
diff --git a/docs/images/CommandComponentClassDiagram.png b/docs/images/CommandComponentClassDiagram.png
new file mode 100644
index 0000000000..4d2b6d64c9
Binary files /dev/null and b/docs/images/CommandComponentClassDiagram.png differ
diff --git a/docs/images/CountSetsRepsDiagram.png b/docs/images/CountSetsRepsDiagram.png
new file mode 100644
index 0000000000..14a6bd8806
Binary files /dev/null and b/docs/images/CountSetsRepsDiagram.png differ
diff --git a/docs/images/DeleteLCalorieDiagram.png b/docs/images/DeleteLCalorieDiagram.png
new file mode 100644
index 0000000000..d2dbcccaa7
Binary files /dev/null and b/docs/images/DeleteLCalorieDiagram.png differ
diff --git a/docs/images/DeleteWorkoutDiagram.png b/docs/images/DeleteWorkoutDiagram.png
new file mode 100644
index 0000000000..16f098eea9
Binary files /dev/null and b/docs/images/DeleteWorkoutDiagram.png differ
diff --git a/docs/images/EndWorkoutCommandDiagram.png b/docs/images/EndWorkoutCommandDiagram.png
new file mode 100644
index 0000000000..ad9b611123
Binary files /dev/null and b/docs/images/EndWorkoutCommandDiagram.png differ
diff --git a/docs/images/ExitCommandDiagram.png b/docs/images/ExitCommandDiagram.png
new file mode 100644
index 0000000000..6ebc888761
Binary files /dev/null and b/docs/images/ExitCommandDiagram.png differ
diff --git a/docs/images/ListCalorieDiagram.png b/docs/images/ListCalorieDiagram.png
new file mode 100644
index 0000000000..648c22bcec
Binary files /dev/null and b/docs/images/ListCalorieDiagram.png differ
diff --git a/docs/images/ListWorkoutDiagram.png b/docs/images/ListWorkoutDiagram.png
new file mode 100644
index 0000000000..c77269c0b7
Binary files /dev/null and b/docs/images/ListWorkoutDiagram.png differ
diff --git a/docs/images/StartWorkoutCommandDiagram.png b/docs/images/StartWorkoutCommandDiagram.png
new file mode 100644
index 0000000000..286325880d
Binary files /dev/null and b/docs/images/StartWorkoutCommandDiagram.png differ
diff --git a/docs/images/StorageComponentDiagram.png b/docs/images/StorageComponentDiagram.png
new file mode 100644
index 0000000000..4df0616d62
Binary files /dev/null and b/docs/images/StorageComponentDiagram.png differ
diff --git a/docs/images/UiComponentClassDiagram.png b/docs/images/UiComponentClassDiagram.png
new file mode 100644
index 0000000000..38c27a9109
Binary files /dev/null and b/docs/images/UiComponentClassDiagram.png differ
diff --git a/docs/images/ViewCalorieDiagram.png b/docs/images/ViewCalorieDiagram.png
new file mode 100644
index 0000000000..daf6441fc5
Binary files /dev/null and b/docs/images/ViewCalorieDiagram.png differ
diff --git a/docs/images/ViewDiagram.png b/docs/images/ViewDiagram.png
new file mode 100644
index 0000000000..1f4d1df956
Binary files /dev/null and b/docs/images/ViewDiagram.png differ
diff --git a/docs/images/WorkoutComponentClassDiagram.png b/docs/images/WorkoutComponentClassDiagram.png
new file mode 100644
index 0000000000..13693d0d41
Binary files /dev/null and b/docs/images/WorkoutComponentClassDiagram.png differ
diff --git a/docs/team/Richardtok.md b/docs/team/Richardtok.md
new file mode 100644
index 0000000000..e30e72126a
--- /dev/null
+++ b/docs/team/Richardtok.md
@@ -0,0 +1,33 @@
+## Project: FITZ
+Our Vision of an all-in-one Fitness app is in "FITZ". This CLI app is perfect for those who are tying to keep fit and healthy.
+With "FITZ" users can easily track their fitness and diet with ease and cna help in achieving their goals.
+This app is specifically designed for users who prefer using an app in CLI format,
+making it a user-friendly option for anyone who wants to keep their fitness and diet goals in check.
+
+### Contributions
+Code Contributions:[RepoCode](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=Richardtok&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17&tabOpen=true&tabType=zoom&zA=coregano&zR=AY2223S2-CS2113-T14-2%2Ftp%5Bmaster%5D&zACS=156.78342687355564&zS=2023-02-17&zFS=&zU=2023-04-10&zMG=false&zFTF=commit&zFGS=groupByRepos&zFR=false)
+
+Implemented Features: Viewing a specific day exercises Workout [#9](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/9)
+- What it does: It enables the user to view the exercises done in a specific day.
+- Justification: It allows users to see what exercises they have done on that day
+
+Implemented Features: Viewing a specific day calorie consumption[#86](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+- What it does: It enables the user to view the food that they have eatan ont hat day and the calories of the food
+- Justification: It allows the user to know what they have consumed on that day and be mindful of the calories they have consumed
+
+Implemented Features: Help function for both Workout Commands and Calorie Commands[#86](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+- What it does: It allows the user to view all the valid commands that can be used for "FITZ"
+- Justification: It summarizes the list of valid commands so that the user can easily use it.
+
+Contributions to the User Guide:[#86](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+- Completely reworked the User Guide with accordance to code changes
+- Added descriptions to every Command and Provided examples
+
+Contributions to the Developer Guide:[#86](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+- Created the sequence Diagrams and explanations of for all the CaloriesCommand, that includes AddCalories, ViewCalories, ListCalories
+and DeleteCalories.
+
+Other Contributions:
+- Cleanup the code, to make it standardized for the coding standard
+- Resolved several problems regarding pull requests[#86](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+- Review PR of other team members [#91](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/91)
\ No newline at end of file
diff --git a/docs/team/calebcjl.md b/docs/team/calebcjl.md
new file mode 100644
index 0000000000..fd5ac01969
--- /dev/null
+++ b/docs/team/calebcjl.md
@@ -0,0 +1,35 @@
+# Caleb Chan Jia Le - Project Portfolio Page
+
+## Project: FITZ
+Fitz is a command line interface app for fitness enthusiast to track their workouts and calorie consumption.
+It is fast, lightweight and easy to use.
+
+
+## Contribution to the project
+
+### Code Contributed:
+[RepoCode](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=calebcjl&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+Features implemented:
+* Main architecture of the program
+* Workout tracker: Start, add, end features
+ * **What it does**: Allows users to start a workout, add exercises as they do their workouts, and end the workout.
+* Calorie tracker: Add, delete, list features
+ * **What it does**: Allows users to add their calorie consumption, delete their wrong entries, and list out
+ calorie consumption for each day.
+ * **Enhancement**: Delete feature can delete either a single food or the entire day's entry.
+* Main Parser and the majority of parsers for calorie tracker and workout tracker
+ * **What it does**: Parses user inputs to the respective commands and their details.
+* Exceptions for incorrect user inputs
+* Storage for calorie tracker
+
+### Documentation
+User Guide:
+* Workout tracker: Start, add, end features
+* Calorie tracker: Add, delete, list features
+
+Developer Guide:
+* Workout tracker: Start, add, end features
+* Calorie tracker: Add, delete, list features
+
+
diff --git a/docs/team/guillaume-grn.md b/docs/team/guillaume-grn.md
new file mode 100644
index 0000000000..2ae5e8c858
--- /dev/null
+++ b/docs/team/guillaume-grn.md
@@ -0,0 +1,44 @@
+# Guillaume Gerony -Project Portfolio Page
+
+## Fitz Overview
+
+Fitz - the ultimate fitness app for individuals who are passionate about their health and fitness.
+Users can achieve their fitness goals and track their progress with ease.
+This innovative app is designed for users who prefer a CLI format,
+making it a user-friendly option for anyone who wants to keep their fitness routine on track.
+
+## Summary of Contributions
+
+### Code contributed
+
+My contributions to the code : [RepoCode](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=guillaume-grn&breakdown=true)
+
+### Enhancements implemented
+
+- Added a feature to allow users to delete a workout
+- Added a feature to allow users to know the count of sets and reps per exercise done within a specific week
+
+### Contributions to the UG
+
+I contributed to the following sections in the User Guide:
+
+- Delete workout
+- Count Sets and Reps
+
+### Contributions to the DG
+
+I contributed to the following sections in the Design Guide:
+
+- Added Delete Workout mechanism description
+- Added the UML sequence diagram for the delete feature
+- Added CountSetsReps mechanism description
+- Added the UML sequence diagram for the Count feature
+
+### Contributions to team-based tasks
+
+- Reviewed several pull requests and provided feedback to my teammates.
+- Helped team members troubleshoot issues they encountered during development.
+- Proposed changes for our repository organization and helped refactor classes and methods accordingly.
+- Tested the application to find and report bugs to the team, or suggest improvements from the user point of view.
+
+
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/zizi-czh.md b/docs/team/zizi-czh.md
new file mode 100644
index 0000000000..0b31f453b4
--- /dev/null
+++ b/docs/team/zizi-czh.md
@@ -0,0 +1,77 @@
+# Chen Zi Han - Project Portfolio Page
+
+## Project: FITZ
+Fitz - the ultimate fitness app for individuals who are passionate about their health and fitness.
+Users can achieve their fitness goals and track their progress with ease.
+This innovative app is designed for users who prefer a CLI format,
+making it a user-friendly option for anyone who wants to keep their fitness routine on track.
+
+
+### Given Below are my contribution to the project
+
+- Code Contributed: [RepoCode](https://nus-cs2113-ay2223s2.github.io/tp-dashboard/?search=ZIZI-CZH&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-02-17)
+
+- Implementation: Added list and view for workout so that the user can track their exercise history
+
+ - What it does: List all the dates and workouts that have been entered by the user before so that they have better insight.
+ - In oder to let the user be more clear about what are the exercise they have done for each workout
+- Implementation: Added storage for workout and food list
+
+ - What is does: record the workouts data that been entered by the users and record the food name and
+ - the food calories so that user do not need to enter the information every time
+
+- Contribute to DG:
+ - Draw sequence diagram, architecture and class diagram for all the components which include Storage, Ui, Workout, Calories
+ - and Parser.
+ - Explain how each component work in details
+
+- Contribute to UG:
+ - Set up
+ - Introduction
+
+
+- Contributions to team based tasks
+-
+ - Contribute to the testing of program
+ - [[1]](https://github.com/AY2223S2-CS2113-T14-1/tp/issues/90)
+ - [[2]](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/89)
+ - Assisted team to fix bugs
+ - Reviewed and Commented on team's PR code with improvement suggestions
+ - [[1]](https://github.com/AY2223S2-CS2113-T14-1/tp/pull/86)
+
+
+
+
+
+This is what l implemented for previous version before V2.1:
+
+- Implemented Features: Starting a New Workout Day and Adding New Workouts
+ - What it Does: Enables users to enter the date they want to begin tracking their fitness progress and add the names of their workouts for that day.
+ - Justification: By allowing users to select the specific date they want to start tracking their workouts, the app becomes more flexible and personalized to their needs.
+ Additionally, allowing users to add multiple workouts for each day enables them to record a more comprehensive view of their exercise routine.
+ - Key Highlights: The app requires users to enter the date before they can begin tracking their workouts, as this is essential for accurate record keeping.
+ Furthermore, the app permits users to add new workouts to previous days' records, in case they missed a workout or want to add a previously unrecorded workout.
+ However, if the user enters the same workout name for a given date, the app will assume it refers to the same workout and update the existing record accordingly.
+
+- Implemented Features: Adding Exercises to Current Workout
+ - What it Does: Enables users to add exercises to their current workout, including the exercise name, weight, and repetitions per set (RPS).
+ - Justification: Users must add exercises to a specific day and workout, similar to adding a new workout. The app allows for the possibility of duplicate exercise sets,
+ since users may want to record multiple sets of the same exercise within a single workout session.
+ - Key Highlights: Users can follow a standardized format to enter their exercise records, including the exercise name, weight used, and RPS.
+ This ensures that the app can accurately record and display the user's workout progress over time.
+
+- Implemented features: List of All Recorded Days and View Workouts by Day
+ - What it Does: Provides users with a list of all the dates they have previously entered into the app,
+ as well as the ability to view their workout records for a specific day.
+ - Justification: The app displays a list of all entered dates, even if no workouts have been recorded for that day, as long as the date was entered in the proper format.
+ Similarly, the view function will display all previously entered workouts for a specific day, even if no exercises were completed on that day.
+ This ensures that users have a clear and comprehensive overview of their exercise history.
+ - Key Highlights: Users can use the list of recorded days and view function to gain insights into their exercise history,
+ which can inform their future workout plans. By providing users with a complete record of their workout history, the app can help users to stay motivated and track their progress over time.
+
+- Implemented features: Workout Data Storage
+ - What it Does: The app automatically saves any changes made to the workout records in an external .txt file when the user exits the app, and retrieves it when the app is opened again.
+ - Justification: Justification: Enabling users to use the app at different times requires a reliable way of storing their data, ensuring that their progress is accurately tracked and readily available.
+ - Key Highlights: Key Highlights: Properly exiting the app is crucial for the workout data to be saved.
+
+
diff --git a/src/main/java/seedu/Duke.java b/src/main/java/seedu/Duke.java
new file mode 100644
index 0000000000..1a80f623c3
--- /dev/null
+++ b/src/main/java/seedu/Duke.java
@@ -0,0 +1,65 @@
+package seedu;
+
+import seedu.calorietracker.CalorieTracker;
+import seedu.calorietracker.FoodDictionary;
+import seedu.commands.Command;
+import seedu.commands.ExitCommand;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+import seedu.parser.Parser;
+import seedu.storage.Storage;
+import seedu.ui.Ui;
+import seedu.workout.WorkoutList;
+
+//@@author calebcjl
+/**
+ * Main entry to the program
+ */
+public class Duke {
+ private WorkoutList workoutList;
+ private CalorieTracker calorieTracker;
+ private FoodDictionary foodDictionary;
+ private Storage storage;
+
+ public Duke() {
+ }
+
+ public static void main(String[] args) {
+ new Duke().run();
+ }
+
+ //@@author calebcjl
+ /**
+ * Runs the program.
+ */
+ private void run() {
+ storage = new Storage();
+ workoutList = new WorkoutList(storage);
+ foodDictionary = new FoodDictionary(storage);
+ calorieTracker = new CalorieTracker(storage, foodDictionary);
+ Ui.showWelcomeMessage();
+ executeCommandUntilExit();
+ }
+
+ //@@author calebcjl
+ /**
+ * Continuously receives and execute commands entered by user.
+ * Stops when user enters exit command.
+ */
+ private void executeCommandUntilExit() {
+ Command command;
+ do {
+ String userInput = Ui.getUserInput();
+ try {
+ command = Parser.parseCommand(userInput);
+ command.setData(workoutList, calorieTracker, foodDictionary);
+ Ui.showCommandResult(command);
+ } catch (InvalidSyntaxException | InvalidArgumentException e) {
+ Ui.showErrorMessage(e.toString());
+ command = new Command();
+ }
+ storage.saveUserData(workoutList, foodDictionary, calorieTracker);
+ } while (!ExitCommand.isExit(command));
+ }
+}
+
diff --git a/src/main/java/seedu/calorietracker/CalorieTracker.java b/src/main/java/seedu/calorietracker/CalorieTracker.java
new file mode 100644
index 0000000000..11aa2ec08a
--- /dev/null
+++ b/src/main/java/seedu/calorietracker/CalorieTracker.java
@@ -0,0 +1,86 @@
+package seedu.calorietracker;
+
+import seedu.exceptions.InvalidSyntaxException;
+import seedu.parser.DateFormatter;
+import seedu.storage.Storage;
+import seedu.ui.Ui;
+
+import java.util.Date;
+import java.util.HashMap;
+
+import static seedu.commands.caloriecommands.AddCalorieCommand.CALORIES_NOT_GIVEN;
+
+
+/**
+ * Represents a calorie tracker.
+ */
+public class CalorieTracker {
+ private final HashMap dailyFoodConsumption;
+ private final FoodDictionary foodDictionary;
+
+
+ //@@author ZIZI-czh
+ /**
+ * Constructs a new CalorieTracker object with the given storage and food dictionary. The
+ * initial daily food consumption records are read from the storage, and the food dictionary
+ * is used to look up food items by their names.
+ *
+ * @param storage the storage object to use for reading and writing the daily food consumption
+ * records
+ * @param foodDictionary the food dictionary object to use for looking up food items by their names
+ */
+ public CalorieTracker(Storage storage, FoodDictionary foodDictionary) {
+ dailyFoodConsumption = storage.readCalorieTrackerFile();
+ this.foodDictionary = foodDictionary;
+ }
+
+ //@@author ZIZI-czh
+ /**
+ * Returns a FoodList representing the list of foods consumed on the specified date. If no
+ * such list exists in the daily food consumption records, a new, empty list is created and
+ * added to the records for that date.
+ *
+ * @param date the date for which to retrieve the list of consumed foods
+ * @return a FoodList object representing the list of foods consumed on the specified date
+ */
+ public FoodList getFoodList(Date date) {
+ if (!dailyFoodConsumption.containsKey(date)) {
+ FoodList foodList = new FoodList();
+ dailyFoodConsumption.put(date, foodList);
+ }
+ return dailyFoodConsumption.get(date);
+ }
+
+ public HashMap getDailyFoodConsumption() {
+ return dailyFoodConsumption;
+ }
+
+ //@@author calebcjl
+ /**
+ * Add calorie consumption to CalorieTracker.
+ *
+ * @param date Date of consumption.
+ * @param foodName Name of food.
+ * @param foodCalories Calories of food.
+ * @return Output string.
+ * @throws InvalidSyntaxException If invalid syntax.
+ */
+ public String addCalories(Date date, String foodName, int foodCalories) throws InvalidSyntaxException {
+ FoodList foodList = getFoodList(date);
+ Food foodToAdd;
+ if (foodCalories == CALORIES_NOT_GIVEN) {
+ if (foodDictionary.contains(foodName)) {
+ foodToAdd = new Food(foodName, foodDictionary.getFoodCalories().get(foodName));
+ } else {
+ throw new InvalidSyntaxException("food calories");
+ }
+ } else {
+ foodToAdd = new Food(foodName, foodCalories);
+ foodDictionary.addFood(foodName, foodCalories);
+ }
+ foodList.addFood(foodToAdd);
+
+ return "Added " + foodName + "(" + foodToAdd.getCalories() + " kcal) to "
+ + DateFormatter.dateToString(date) + "." + System.lineSeparator() + Ui.line();
+ }
+}
diff --git a/src/main/java/seedu/calorietracker/Food.java b/src/main/java/seedu/calorietracker/Food.java
new file mode 100644
index 0000000000..53ee73901d
--- /dev/null
+++ b/src/main/java/seedu/calorietracker/Food.java
@@ -0,0 +1,23 @@
+package seedu.calorietracker;
+
+//@@author calebcjl
+/**
+ * Represents food consumed.
+ */
+public class Food {
+ private final String foodName;
+ private final int calories;
+
+ public Food(String foodName, int calories) {
+ this.foodName = foodName;
+ this.calories = calories;
+ }
+
+ public String getFoodName() {
+ return foodName;
+ }
+
+ public int getCalories() {
+ return calories;
+ }
+}
diff --git a/src/main/java/seedu/calorietracker/FoodDictionary.java b/src/main/java/seedu/calorietracker/FoodDictionary.java
new file mode 100644
index 0000000000..0e15a8d47f
--- /dev/null
+++ b/src/main/java/seedu/calorietracker/FoodDictionary.java
@@ -0,0 +1,29 @@
+package seedu.calorietracker;
+
+import seedu.storage.Storage;
+
+import java.util.HashMap;
+
+//@@author calebcjl
+/**
+ * Represents a dictionary that maps food to its calorie count.
+ */
+public class FoodDictionary {
+ private final HashMap foodCalories;
+
+ public FoodDictionary(Storage storage) {
+ this.foodCalories = storage.readFoodDictionaryFile();
+ }
+
+ public void addFood(String name, int calories) {
+ foodCalories.put(name, calories);
+ }
+
+ public boolean contains(String food) {
+ return foodCalories.containsKey(food);
+ }
+
+ public HashMap getFoodCalories() {
+ return foodCalories;
+ }
+}
diff --git a/src/main/java/seedu/calorietracker/FoodList.java b/src/main/java/seedu/calorietracker/FoodList.java
new file mode 100644
index 0000000000..64389ec86d
--- /dev/null
+++ b/src/main/java/seedu/calorietracker/FoodList.java
@@ -0,0 +1,39 @@
+package seedu.calorietracker;
+
+import java.util.ArrayList;
+
+//@@author calebcjl
+/**
+ * Represents a list of food eaten in a single day.
+ */
+public class FoodList {
+ private final ArrayList foods;
+ private int totalCalories;
+
+ public FoodList() {
+ foods = new ArrayList<>();
+ totalCalories = 0;
+ }
+
+ public void addFood(Food food) {
+ foods.add(food);
+ totalCalories += food.getCalories();
+ }
+
+ public ArrayList getFoods() {
+ return foods;
+ }
+
+ public Food getFood(int index) {
+ return foods.get(index);
+ }
+
+ public int getTotalCalories() {
+ return totalCalories;
+ }
+
+ public void deleteFood(int index) {
+ totalCalories -= foods.get(index).getCalories();
+ foods.remove(index);
+ }
+}
diff --git a/src/main/java/seedu/commands/Command.java b/src/main/java/seedu/commands/Command.java
new file mode 100644
index 0000000000..331d6f8e23
--- /dev/null
+++ b/src/main/java/seedu/commands/Command.java
@@ -0,0 +1,38 @@
+package seedu.commands;
+
+import seedu.calorietracker.CalorieTracker;
+import seedu.calorietracker.FoodDictionary;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+import seedu.workout.WorkoutList;
+
+//@@author calebcjl
+/**
+ * Represents a command entered by user.
+ */
+public class Command {
+
+ protected WorkoutList workoutList;
+ protected CalorieTracker calorieTracker;
+ protected FoodDictionary foodDictionary;
+
+ public Command() {
+ }
+
+ /**
+ * Sets data for commands to execute on.
+ *
+ * @param workoutList Workout list.
+ * @param calorieTracker Calorie tracker.
+ * @param foodDictionary Food list.
+ */
+ public void setData(WorkoutList workoutList, CalorieTracker calorieTracker, FoodDictionary foodDictionary) {
+ this.workoutList = workoutList;
+ this.calorieTracker = calorieTracker;
+ this.foodDictionary = foodDictionary;
+ }
+
+ public String execute() throws InvalidArgumentException, InvalidSyntaxException {
+ throw new UnsupportedOperationException("This method is to be implemented by child classes");
+ }
+}
diff --git a/src/main/java/seedu/commands/ExitCommand.java b/src/main/java/seedu/commands/ExitCommand.java
new file mode 100644
index 0000000000..9c3cb8e9fe
--- /dev/null
+++ b/src/main/java/seedu/commands/ExitCommand.java
@@ -0,0 +1,26 @@
+package seedu.commands;
+
+import seedu.ui.Ui;
+
+//@@author calebcjl
+/**
+ * Represents command to exit the program.
+ */
+public class ExitCommand extends Command {
+ private static final String EXIT_MESSAGE = "Thank you, hope you had a great workout!!!";
+
+ /**
+ * Check if exit command has been created.
+ *
+ * @param command Command to check.
+ * @return True if command is an ExitCommand. Returns false otherwise.
+ */
+ public static boolean isExit(Command command) {
+ return command instanceof ExitCommand;
+ }
+
+ @Override
+ public String execute() {
+ return EXIT_MESSAGE + System.lineSeparator() + Ui.line();
+ }
+}
diff --git a/src/main/java/seedu/commands/caloriecommands/AddCalorieCommand.java b/src/main/java/seedu/commands/caloriecommands/AddCalorieCommand.java
new file mode 100644
index 0000000000..cf50505eba
--- /dev/null
+++ b/src/main/java/seedu/commands/caloriecommands/AddCalorieCommand.java
@@ -0,0 +1,50 @@
+package seedu.commands.caloriecommands;
+
+import seedu.commands.Command;
+import seedu.exceptions.InvalidSyntaxException;
+
+import java.util.Date;
+
+//@@author calebcjl
+/**
+ * Represents command to add an entry to calorie tracker.
+ */
+public class AddCalorieCommand extends Command {
+ public static final int CALORIES_NOT_GIVEN = -1;
+ private final Date date;
+ private final String foodName;
+ private final int foodCalories;
+
+
+ /**
+ * Constructs an instance of AddCalorieCommand with the specified date, food name, and calorie intake.
+ *
+ * @param date the date of the food log
+ * @param foodName the name of the food
+ * @param foodCalories the calorie intake of the food
+ */
+ public AddCalorieCommand(Date date, String foodName, int foodCalories) {
+ this.date = date;
+ this.foodName = foodName;
+ this.foodCalories = foodCalories;
+ }
+
+
+ /**
+ * Constructs an instance of AddCalorieCommand with the specified date and food name, with the calorie intake
+ * set to a default value of CALORIES_NOT_GIVEN.
+ *
+ * @param date the date of the food log
+ * @param foodName the name of the food
+ */
+ public AddCalorieCommand(Date date, String foodName) {
+ this.date = date;
+ this.foodName = foodName;
+ foodCalories = CALORIES_NOT_GIVEN;
+ }
+
+ @Override
+ public String execute() throws InvalidSyntaxException {
+ return calorieTracker.addCalories(date, foodName, foodCalories);
+ }
+}
diff --git a/src/main/java/seedu/commands/caloriecommands/DeleteCalorieCommand.java b/src/main/java/seedu/commands/caloriecommands/DeleteCalorieCommand.java
new file mode 100644
index 0000000000..14457cd61b
--- /dev/null
+++ b/src/main/java/seedu/commands/caloriecommands/DeleteCalorieCommand.java
@@ -0,0 +1,40 @@
+package seedu.commands.caloriecommands;
+
+import seedu.calorietracker.Food;
+import seedu.commands.Command;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+import seedu.parser.DateFormatter;
+
+import java.util.Date;
+
+//@@author calebcjl
+/**
+ * Represents command to delete calorie consumption entry.
+ */
+public class DeleteCalorieCommand extends Command {
+ public static final int NO_INDEX = -1;
+ private Date date;
+ private int index;
+ public DeleteCalorieCommand(Date date) {
+ this.date = date;
+ index = NO_INDEX;
+ }
+
+ public DeleteCalorieCommand(Date date, int index) {
+ this.date = date;
+ this.index = index;
+ }
+
+ @Override
+ public String execute() throws InvalidArgumentException, InvalidSyntaxException {
+ if (index == NO_INDEX) {
+ calorieTracker.getDailyFoodConsumption().remove(date);
+ return "Deleted calorie consumption on " + DateFormatter.dateToString(date) + '.';
+ }
+ Food deletedFood = calorieTracker.getDailyFoodConsumption().get(date).getFood(index);
+ calorieTracker.getDailyFoodConsumption().get(date).deleteFood(index);
+ return "Deleted " + deletedFood.getFoodName() + "(" + deletedFood.getCalories() + " kcal) from "
+ + DateFormatter.dateToString(date);
+ }
+}
diff --git a/src/main/java/seedu/commands/caloriecommands/HelpCaloriesCommand.java b/src/main/java/seedu/commands/caloriecommands/HelpCaloriesCommand.java
new file mode 100644
index 0000000000..3830e774cd
--- /dev/null
+++ b/src/main/java/seedu/commands/caloriecommands/HelpCaloriesCommand.java
@@ -0,0 +1,13 @@
+package seedu.commands.caloriecommands;
+
+import seedu.commands.Command;
+import seedu.ui.Ui;
+
+public class HelpCaloriesCommand extends Command {
+
+ @Override
+ public String execute() {
+ return Ui.getCaloriesHelpMessage();
+ }
+
+}
diff --git a/src/main/java/seedu/commands/caloriecommands/ListCaloriesCommand.java b/src/main/java/seedu/commands/caloriecommands/ListCaloriesCommand.java
new file mode 100644
index 0000000000..403090d0e1
--- /dev/null
+++ b/src/main/java/seedu/commands/caloriecommands/ListCaloriesCommand.java
@@ -0,0 +1,38 @@
+package seedu.commands.caloriecommands;
+
+import seedu.calorietracker.FoodList;
+import seedu.commands.Command;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+
+import java.util.Date;
+import java.util.TreeMap;
+
+//@@author calebcjl
+/**
+ * Represents list calories command.
+ */
+public class ListCaloriesCommand extends Command {
+ private static final String EMPTY_LIST_MESSAGE = "Calorie consumption list is empty!";
+ private static final String HEADER =
+ "Here is your list of daily calorie consumption: " + System.lineSeparator();
+ public ListCaloriesCommand() {
+ }
+
+ @Override
+ public String execute() {
+ if (calorieTracker.getDailyFoodConsumption().isEmpty()) {
+ return EMPTY_LIST_MESSAGE;
+ }
+
+ TreeMap sortedMap = new TreeMap<>(calorieTracker.getDailyFoodConsumption());
+ StringBuilder stringBuilder = new StringBuilder(HEADER);
+ int counter = 1;
+ for (Date date: sortedMap.keySet()) {
+ stringBuilder.append(counter).append(". ").append(DateFormatter.dateToString(date)).append(": ")
+ .append(sortedMap.get(date).getTotalCalories()).append("kcal").append(System.lineSeparator());
+ counter += 1;
+ }
+ return stringBuilder.append(Ui.line()).toString();
+ }
+}
diff --git a/src/main/java/seedu/commands/caloriecommands/ViewCaloriesCommand.java b/src/main/java/seedu/commands/caloriecommands/ViewCaloriesCommand.java
new file mode 100644
index 0000000000..c7009ff814
--- /dev/null
+++ b/src/main/java/seedu/commands/caloriecommands/ViewCaloriesCommand.java
@@ -0,0 +1,37 @@
+package seedu.commands.caloriecommands;
+
+import seedu.calorietracker.Food;
+import seedu.commands.Command;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+
+import java.util.Date;
+
+//@@author Richardtok
+public class ViewCaloriesCommand extends Command {
+ private static final String HEADER = "Here are the foods consumed on ";
+ private static final String FAIL_TO_FIND_DATE = " does not exit in the list";
+ private final Date caloriesToViewDate;
+
+ public ViewCaloriesCommand(Date caloriesToViewDate) {
+ this.caloriesToViewDate = caloriesToViewDate;
+ }
+
+
+ @Override
+ public String execute() {
+ if (!calorieTracker.getDailyFoodConsumption().containsKey(caloriesToViewDate)) {
+ return DateFormatter.dateToString(caloriesToViewDate) + FAIL_TO_FIND_DATE;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder(HEADER + DateFormatter.dateToString(caloriesToViewDate)
+ + ':' + System.lineSeparator());
+ int counter = 1;
+ for (Food food :calorieTracker.getDailyFoodConsumption().get(caloriesToViewDate).getFoods()) {
+ stringBuilder.append(counter).append(". ").append(food.getFoodName()).append(" - ")
+ .append(food.getCalories()).append("kcal").append(System.lineSeparator());
+ counter += 1;
+ }
+ return stringBuilder.append(Ui.line()).toString();
+ }
+}
diff --git a/src/main/java/seedu/commands/errorcommands/IncorrectSyntaxCommand.java b/src/main/java/seedu/commands/errorcommands/IncorrectSyntaxCommand.java
new file mode 100644
index 0000000000..2f23b3376e
--- /dev/null
+++ b/src/main/java/seedu/commands/errorcommands/IncorrectSyntaxCommand.java
@@ -0,0 +1,23 @@
+package seedu.commands.errorcommands;
+
+import seedu.commands.Command;
+import seedu.ui.Ui;
+
+//@@author calebcjl
+/**
+ * Represents a command entered with incorrect syntax.
+ */
+public class IncorrectSyntaxCommand extends Command {
+ private static final String ERROR_MESSAGE = "Invalid syntax for ";
+ private final String syntaxError;
+
+ public IncorrectSyntaxCommand(String syntaxError) {
+ this.syntaxError = syntaxError;
+ }
+
+ @Override
+ public String execute() {
+ return ERROR_MESSAGE + syntaxError + System.lineSeparator() + Ui.line();
+ }
+}
+
diff --git a/src/main/java/seedu/commands/errorcommands/InvalidCommand.java b/src/main/java/seedu/commands/errorcommands/InvalidCommand.java
new file mode 100644
index 0000000000..b263603447
--- /dev/null
+++ b/src/main/java/seedu/commands/errorcommands/InvalidCommand.java
@@ -0,0 +1,22 @@
+package seedu.commands.errorcommands;
+
+import seedu.commands.Command;
+import seedu.ui.Ui;
+
+//@@author calebcjl
+/**
+ * Represents an invalid command
+ */
+public class InvalidCommand extends Command {
+ private static final String INVALID_COMMAND_MESSAGE = " is not a valid command!";
+ private final String command;
+ public InvalidCommand(String command) {
+ this.command = command;
+ }
+
+ @Override
+ public String execute() {
+ return command + INVALID_COMMAND_MESSAGE + System.lineSeparator() + Ui.line();
+ }
+}
+
diff --git a/src/main/java/seedu/commands/workoutcommands/AddExerciseCommand.java b/src/main/java/seedu/commands/workoutcommands/AddExerciseCommand.java
new file mode 100644
index 0000000000..447cb6db3b
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/AddExerciseCommand.java
@@ -0,0 +1,37 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+
+import static seedu.workout.WorkoutList.NO_CURRENT_WORKOUT;
+
+//@@author calebcjl
+/**
+ * Represents command to add an exercise to the current workout.
+ */
+public class AddExerciseCommand extends Command {
+ private static final String EXERCISE_ADDED_MESSAGE = " has been added.";
+ private static final String NO_CURRENT_WORKOUT_MESSAGE = "Start a workout before adding exercises!";
+ private final Exercise exerciseToAdd;
+
+ public AddExerciseCommand(Exercise exerciseToAdd) {
+ this.exerciseToAdd = exerciseToAdd;
+ }
+
+ /**
+ * Executes the command to add the exercise to the current workout.
+ * If there is no current workout ongoing, exercise will not be added.
+ *
+ * @return Exercise added message if successful. Returns no current workout message otherwise.
+ */
+ @Override
+ public String execute() {
+ if (workoutList.getCurrentWorkoutIndex() == NO_CURRENT_WORKOUT) {
+ return NO_CURRENT_WORKOUT_MESSAGE;
+ }
+ Workout currentWorkout = workoutList.getCurrentWorkout();
+ currentWorkout.addExercise(exerciseToAdd);
+ return exerciseToAdd + EXERCISE_ADDED_MESSAGE;
+ }
+}
diff --git a/src/main/java/seedu/commands/workoutcommands/CountSetsRepsCommand.java b/src/main/java/seedu/commands/workoutcommands/CountSetsRepsCommand.java
new file mode 100644
index 0000000000..81b113ff84
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/CountSetsRepsCommand.java
@@ -0,0 +1,20 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+
+import java.util.Date;
+
+//@@author guillaume-grn
+public class CountSetsRepsCommand extends Command {
+ private final Date dayInSpecificWeekDate;
+
+
+ public CountSetsRepsCommand(Date dayInSpecificWeekDate) {
+ this.dayInSpecificWeekDate = dayInSpecificWeekDate;
+ }
+
+ @Override
+ public String execute() {
+ return workoutList.countSetsReps(dayInSpecificWeekDate);
+ }
+}
diff --git a/src/main/java/seedu/commands/workoutcommands/DeleteWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/DeleteWorkoutCommand.java
new file mode 100644
index 0000000000..5d7b85c885
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/DeleteWorkoutCommand.java
@@ -0,0 +1,47 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+import seedu.workout.WorkoutList;
+
+import java.util.Date;
+
+//@@ author ZIZI-czh
+/**
+ * Represents a command to delete a workout from the workout list, identified by the index of the workout to delete.
+ * The index of the workout to delete is passed in through the constructor.
+ */
+public class DeleteWorkoutCommand extends Command {
+ private final int workoutToDeleteIndex;
+
+ //@@ author ZIZI-czh
+ /**
+ * Creates a new instance of DeleteWorkoutCommand with the specified index of the workout to delete.
+ * @param workoutToDeleteIndex the index of the workout to delete
+ */
+ public DeleteWorkoutCommand(int workoutToDeleteIndex) {
+ this.workoutToDeleteIndex = workoutToDeleteIndex;
+ }
+
+ //This one is for JUnit Test
+ public DeleteWorkoutCommand(WorkoutList workoutListParameter, int workoutToDeleteIndex) {
+ this.workoutToDeleteIndex = workoutToDeleteIndex;
+ workoutList = workoutListParameter;
+ }
+
+ //@@author calebcjl
+ @Override
+ public String execute() throws InvalidArgumentException {
+ if (workoutToDeleteIndex==-1 || workoutToDeleteIndex >= workoutList.getWorkouts().size()) {
+ throw new InvalidArgumentException("index, indexes range from 1 to " + workoutList.getWorkouts().size());
+ }
+
+ String workoutName = workoutList.getWorkout(workoutToDeleteIndex).getWorkoutName();
+ Date workoutDate = workoutList.getWorkout(workoutToDeleteIndex).getDate();
+ workoutList.deleteWorkout(workoutToDeleteIndex);
+ return "Deleted " + workoutName + " on " + DateFormatter.dateToString(workoutDate) + '.';
+ }
+}
+
+
diff --git a/src/main/java/seedu/commands/workoutcommands/EndWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/EndWorkoutCommand.java
new file mode 100644
index 0000000000..3918a70ab1
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/EndWorkoutCommand.java
@@ -0,0 +1,33 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+
+import static seedu.workout.WorkoutList.NO_CURRENT_WORKOUT;
+
+//@@author calebcjl
+/**
+ * Represents command to end the current workout.
+ */
+public class EndWorkoutCommand extends Command {
+ private static final String NO_CURRENT_WORKOUT_MESSAGE = "No ongoing workout to end!";
+ private static final String WORKOUT_COMPLETE_MESSAGE = "Great job completing your workout!";
+
+ public EndWorkoutCommand() {
+ }
+
+ /**
+ * Ends the current workout.
+ * If there is no current workout ongoing, no workout will be ended.
+ *
+ * @return Returns workout completed message if current workout is ended. Returns no current workout
+ * message otherwise.
+ */
+ @Override
+ public String execute() {
+ if (workoutList.getCurrentWorkoutIndex() == NO_CURRENT_WORKOUT) {
+ return NO_CURRENT_WORKOUT_MESSAGE;
+ }
+ workoutList.setCurrentWorkoutIndex(NO_CURRENT_WORKOUT);
+ return WORKOUT_COMPLETE_MESSAGE;
+ }
+}
diff --git a/src/main/java/seedu/commands/workoutcommands/HelpWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/HelpWorkoutCommand.java
new file mode 100644
index 0000000000..cd1b532dcf
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/HelpWorkoutCommand.java
@@ -0,0 +1,13 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.ui.Ui;
+//@@author Richardtok
+public class HelpWorkoutCommand extends Command {
+ public HelpWorkoutCommand(){}
+
+ @Override
+ public String execute() {
+ return Ui.getWorkoutHelpMessage();
+ }
+}
diff --git a/src/main/java/seedu/commands/workoutcommands/ListWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/ListWorkoutCommand.java
new file mode 100644
index 0000000000..bb5dd0cfe8
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/ListWorkoutCommand.java
@@ -0,0 +1,53 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+//@@ author ZIZI-czh
+/**
+ * This is the class for executing the list command
+ */
+public class ListWorkoutCommand extends Command {
+
+ private static final String EMPTY_LIST_MESSAGE = "Workout list is empty";
+ private static final String WORKOUT_LIST_HEADER =
+ "Here is the list of dates of your workouts:" + System.lineSeparator();
+
+ //@@ author ZIZI-czh
+ public ListWorkoutCommand() {
+ }
+
+ public ListWorkoutCommand(WorkoutList workoutListParameter) {
+ workoutList = workoutListParameter;
+ }
+
+ //@@author ZIZI-czh
+ /**
+ * Executes the command to display a list of all the workouts in the workout list.
+ * If the workout list is empty, returns a message indicating that the list is empty.
+ * @return a string representation of the list of workouts, including their respective dates and names
+ */
+ @Override
+ public String execute() {
+
+ if (workoutList.isEmptyList()) {
+ return EMPTY_LIST_MESSAGE;
+ }
+
+ StringBuilder listOfWorkouts = new StringBuilder(WORKOUT_LIST_HEADER);
+ int counter = 1;
+ for (Workout workout : workoutList.getWorkouts()) {
+ String listNumber = counter + ". ";
+ String date = DateFormatter.dateToString(workout.getDate()) + ' ';
+ String workoutName = workout.getWorkoutName();
+ listOfWorkouts.append(listNumber).append(date).append(workoutName).append(System.lineSeparator());
+ counter += 1;
+ }
+ return listOfWorkouts.append(Ui.line()).toString();
+ }
+}
+
+
diff --git a/src/main/java/seedu/commands/workoutcommands/StartWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/StartWorkoutCommand.java
new file mode 100644
index 0000000000..b6b2416089
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/StartWorkoutCommand.java
@@ -0,0 +1,49 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+
+import java.util.Date;
+
+import static seedu.workout.WorkoutList.NO_CURRENT_WORKOUT;
+
+//@@author calebcjl
+/**
+ * Represents command to start a new workout on the current date.
+ */
+public class StartWorkoutCommand extends Command {
+ private static final String ONGOING_WORKOUT_MESSAGE = "There is already an ongoing workout!";
+ private final String workoutName;
+ private final Date date;
+
+
+ /**
+ * Represents a command to start a new workout with the specified date and workout name.
+ *
+ * @param date the date of the new workout
+ * @param workoutName the name of the new workout
+ */
+ public StartWorkoutCommand(Date date, String workoutName) {
+ this.date = date;
+ this.workoutName = workoutName;
+ }
+
+ /**
+ * Executes the command to start a new workout.
+ * Only start a new workout if there is no current workout ongoing.
+ * It will not start the workout if there already exists a workout with the same name and date.
+ *
+ * @return Workout start message if workout is started. Returns ongoing workout message.
+ * @throws InvalidArgumentException If name and date of workout to be added is the same as a workout that
+ * is already in the workout list.
+ */
+ @Override
+ public String execute() throws InvalidArgumentException {
+ if (workoutList.getCurrentWorkoutIndex() != NO_CURRENT_WORKOUT) {
+ return ONGOING_WORKOUT_MESSAGE;
+ }
+ workoutList.startWorkout(date, workoutName);
+ return workoutName + " started on " + DateFormatter.dateToString(date) + '.';
+ }
+}
diff --git a/src/main/java/seedu/commands/workoutcommands/ViewWorkoutCommand.java b/src/main/java/seedu/commands/workoutcommands/ViewWorkoutCommand.java
new file mode 100644
index 0000000000..a4ab75b23b
--- /dev/null
+++ b/src/main/java/seedu/commands/workoutcommands/ViewWorkoutCommand.java
@@ -0,0 +1,48 @@
+package seedu.commands.workoutcommands;
+
+import seedu.commands.Command;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+//@@ author ZIZI-czh
+
+/**
+ * View the workout on current date
+ */
+public class ViewWorkoutCommand extends Command {
+ private final int workoutToViewIndex;
+
+ //@@ author ZIZI-czh
+ /**
+ * Represents a command to view a specific workout from the workout list.
+ *
+ * @param workoutToViewIndex the index of the workout to view
+ */
+ public ViewWorkoutCommand(int workoutToViewIndex) {
+ this.workoutToViewIndex = workoutToViewIndex;
+ }
+
+
+ //@@author ZIZI-czh
+ //used for Junit Test
+ public ViewWorkoutCommand(WorkoutList workoutListParamter, int workoutToViewIndex) {
+ this.workoutToViewIndex = workoutToViewIndex;
+ workoutList = workoutListParamter;
+ }
+ //@@ author ZIZI-czh
+ /**
+ * Executes the command to view a specific workout and returns its string representation.
+ *
+ * @return a string representing the workout to view
+ * @throws InvalidArgumentException if the workout index is invalid
+ */
+ @Override
+ public String execute() throws InvalidArgumentException {
+ if (workoutToViewIndex >= workoutList.getWorkouts().size() || workoutToViewIndex==-1) {
+ throw new InvalidArgumentException("index, indexes range from 1 to " + workoutList.getWorkouts().size());
+ }
+ Workout toView = workoutList.getWorkout(workoutToViewIndex);
+ return toView.toString();
+ }
+}
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
deleted file mode 100644
index 5c74e68d59..0000000000
--- a/src/main/java/seedu/duke/Duke.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.duke;
-
-import java.util.Scanner;
-
-public class Duke {
- /**
- * Main entry-point for the java.duke.Duke application.
- */
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- System.out.println("What is your name?");
-
- Scanner in = new Scanner(System.in);
- System.out.println("Hello " + in.nextLine());
- }
-}
diff --git a/src/main/java/seedu/exceptions/InvalidArgumentException.java b/src/main/java/seedu/exceptions/InvalidArgumentException.java
new file mode 100644
index 0000000000..ddef2f546c
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidArgumentException.java
@@ -0,0 +1,19 @@
+package seedu.exceptions;
+
+//@@author calebcjl
+/**
+ * Represents an exception that is thrown when user enters an invalid argument for a command.
+ */
+public class InvalidArgumentException extends Exception {
+ private static final String ERROR_MESSAGE = "Invalid input for ";
+ private final String invalidArgument;
+
+ public InvalidArgumentException(String invalidArgument) {
+ this.invalidArgument = invalidArgument;
+ }
+
+ @Override
+ public String toString() {
+ return ERROR_MESSAGE + invalidArgument + '!';
+ }
+}
diff --git a/src/main/java/seedu/exceptions/InvalidSyntaxException.java b/src/main/java/seedu/exceptions/InvalidSyntaxException.java
new file mode 100644
index 0000000000..ec2aac2603
--- /dev/null
+++ b/src/main/java/seedu/exceptions/InvalidSyntaxException.java
@@ -0,0 +1,19 @@
+package seedu.exceptions;
+
+//@@author calebcjl
+/**
+ * Represents an exception that is thrown when user enters an incorrect syntax for a command.
+ */
+public class InvalidSyntaxException extends Exception {
+ private static final String ERROR_MESSAGE = "Syntax error for ";
+ private final String syntaxError;
+
+ public InvalidSyntaxException(String syntaxError) {
+ this.syntaxError = syntaxError;
+ }
+
+ @Override
+ public String toString() {
+ return ERROR_MESSAGE + syntaxError + '!';
+ }
+}
diff --git a/src/main/java/seedu/parser/CalorieParser.java b/src/main/java/seedu/parser/CalorieParser.java
new file mode 100644
index 0000000000..9dadfcefd4
--- /dev/null
+++ b/src/main/java/seedu/parser/CalorieParser.java
@@ -0,0 +1,141 @@
+package seedu.parser;
+
+import seedu.commands.Command;
+import seedu.commands.caloriecommands.AddCalorieCommand;
+import seedu.commands.caloriecommands.DeleteCalorieCommand;
+import seedu.commands.caloriecommands.ListCaloriesCommand;
+import seedu.commands.caloriecommands.ViewCaloriesCommand;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+
+import java.util.Date;
+import java.util.regex.Pattern;
+
+import static seedu.parser.Parser.parseDate;
+
+//@@author calebcjl
+/**
+ * Represents the parser for calorie commands.
+ */
+public class CalorieParser {
+ private static final int DATE_LENGTH = 8;
+ public CalorieParser() {
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses arguments for AddCalorieCommand.
+ *
+ * @param arguments Arguments to parse.
+ * @return AddCalorieCommand.
+ * @throws InvalidArgumentException If arguments are invalid.
+ */
+ public static Command parseAddCalorieCommand(String arguments)
+ throws InvalidArgumentException, InvalidSyntaxException {
+ arguments = arguments.trim();
+ Date date;
+ String foodName;
+ int foodCalories;
+ try {
+ date = parseDate(arguments.substring(0,DATE_LENGTH));
+ if (Pattern.compile("\\D+")
+ .matcher(arguments.substring(arguments.length() - 1)).matches()) {
+ return new AddCalorieCommand(date, arguments.substring(DATE_LENGTH).trim());
+ }
+ foodName = parseFoodName(arguments);
+ foodCalories =
+ Integer.parseUnsignedInt(arguments.substring(arguments.lastIndexOf(" ")).trim());
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentException("calories");
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidSyntaxException("/cadd command");
+ }
+ return new AddCalorieCommand(date, foodName, foodCalories);
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses food name for AddCalorieCommand.
+ *
+ * @param arguments Arguments to parse.
+ * @return Food name.
+ * @throws InvalidArgumentException If food name is not valid.
+ */
+ private static String parseFoodName(String arguments) throws InvalidArgumentException {
+ String foodName = arguments.substring(DATE_LENGTH, arguments.lastIndexOf(" ")).trim();
+ if (!isValidFoodName(foodName)) {
+ throw new InvalidArgumentException("food name");
+ }
+ return foodName;
+ }
+
+ //@@author calebcjl
+ /**
+ * Check if food name is valid.
+ * A valid food name must not have numbers in it.
+ *
+ * @param foodName Name of food.
+ * @return True if food name is valid. Returns false otherwise.
+ */
+ private static boolean isValidFoodName(String foodName){
+ if (foodName.isEmpty()) {
+ return false;
+ }
+ if (foodName.contains("\\d+")){
+ return false;
+ }
+ return true;
+ }
+
+ //@@author Richardtok
+ public static Command parseViewCaloriesCommand(String arguments)
+ throws InvalidArgumentException, InvalidSyntaxException {
+ Date date;
+ date = parseDate(arguments.trim());
+ return new ViewCaloriesCommand(date);
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses arguments for ListCaloriesCommand.
+ *
+ * @param arguments Argument for command.
+ * @return ListCaloriesCommand.
+ * @throws InvalidSyntaxException If invalid syntax.
+ */
+ public static Command parseListCalorieCommand(String arguments) throws InvalidSyntaxException {
+ if (!arguments.isBlank()) {
+ throw new InvalidSyntaxException("/clist command");
+ }
+ return new ListCaloriesCommand();
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses arguments for DeleteCalorieCommand.
+ *
+ * @param arguments Argument for command.
+ * @return DeleteCalorieCommand.
+ * @throws InvalidArgumentException If invalid argument.
+ * @throws InvalidSyntaxException If invalid syntax.
+ */
+ public static Command parseDeleteCalorieCommand(String arguments)
+ throws InvalidArgumentException, InvalidSyntaxException {
+ arguments = arguments.trim();
+ String[] deleteDetails = arguments.split("\\s+");
+ Date date = parseDate(deleteDetails[0]);
+ if (deleteDetails.length == 1) {
+ return new DeleteCalorieCommand(date);
+ } else if (deleteDetails.length > 2) {
+ throw new InvalidSyntaxException("/cdelete command");
+ }
+
+ int index;
+ try {
+ index = Integer.parseUnsignedInt(deleteDetails[1]) - 1;
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentException("index");
+ }
+ return new DeleteCalorieCommand(date, index);
+ }
+}
diff --git a/src/main/java/seedu/parser/DateFormatter.java b/src/main/java/seedu/parser/DateFormatter.java
new file mode 100644
index 0000000000..1a2b7fdf8e
--- /dev/null
+++ b/src/main/java/seedu/parser/DateFormatter.java
@@ -0,0 +1,38 @@
+package seedu.parser;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+//@@author calebcjl
+/**
+ * This class parses date into a string and vice versa.
+ */
+public class DateFormatter {
+ private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
+
+ public DateFormatter() {
+ }
+
+ /**
+ * Checks if string is in dd/MM/yy format and converts it into date.
+ *
+ * @param date String to be checked.
+ * @return Corresponding date of string.
+ * @throws ParseException If string is not in dd/MM/yy format.
+ */
+ public static Date stringToDate(String date) throws ParseException {
+ return dateFormat.parse(date);
+ }
+
+ /**
+ * Converts date to a string in dd/MM/yy format.
+ *
+ * @param date Date to be converted.
+ * @return String of date in dd/MM/yy format.
+ */
+ public static String dateToString(Date date){
+ return dateFormat.format(date);
+ }
+}
+
diff --git a/src/main/java/seedu/parser/Parser.java b/src/main/java/seedu/parser/Parser.java
new file mode 100644
index 0000000000..4e4899cb3f
--- /dev/null
+++ b/src/main/java/seedu/parser/Parser.java
@@ -0,0 +1,89 @@
+package seedu.parser;
+
+import seedu.commands.Command;
+import seedu.commands.ExitCommand;
+import seedu.commands.caloriecommands.HelpCaloriesCommand;
+import seedu.commands.errorcommands.InvalidCommand;
+import seedu.commands.workoutcommands.HelpWorkoutCommand;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+//@@author calebcjl
+/**
+ * Represents the main parser that parses user commands.
+ */
+public class Parser {
+ private static final Pattern BASIC_COMMAND_FORMAT =
+ Pattern.compile("(?\\S+)(?.*)");
+
+ public static Command parseCommand(String userInput) throws InvalidSyntaxException, InvalidArgumentException {
+ Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+ if (!matcher.matches()) {
+ throw new InvalidSyntaxException("user input");
+ }
+
+ String commandName = matcher.group("commandName");
+ String arguments = matcher.group("arguments");
+
+ //@@author ZIZI-czh
+ switch (commandName.toLowerCase()) {
+ case "/wstart":
+ return WorkoutParser.parseStartWorkoutCommand(arguments);
+ case "/wadd":
+ return WorkoutParser.parseAddExerciseCommand(arguments);
+ case "/wdelete":
+ return WorkoutParser.parseDeleteWorkoutCommand(arguments);
+ case "/wlist":
+ return WorkoutParser.parseListWorkoutCommand(arguments);
+ case "/wview":
+ return WorkoutParser.parseViewWorkoutCommand(arguments);
+ case "/wcount":
+ return WorkoutParser.parseSetsRepsCountCommand(arguments);
+ case "/wend":
+ return WorkoutParser.parseEndWorkoutCommand(arguments);
+ case "/whelp":
+ return new HelpWorkoutCommand();
+ case "/cadd":
+ return CalorieParser.parseAddCalorieCommand(arguments);
+ case "/clist":
+ return CalorieParser.parseListCalorieCommand(arguments);
+ case "/cview":
+ return CalorieParser.parseViewCaloriesCommand(arguments);
+ case "/cdelete":
+ return CalorieParser.parseDeleteCalorieCommand(arguments);
+ case "/chelp":
+ return new HelpCaloriesCommand();
+ case "/exit":
+ return new ExitCommand();
+ default:
+ return new InvalidCommand(commandName);
+ }
+ }
+
+ /**
+ * This method is used to check the input date format
+ *
+ * @param arguments inputs date
+ * @return return null if the date format is invalid
+ */
+ //@@ author ZIZI-czh
+ static Date parseDate(String arguments) throws InvalidSyntaxException, InvalidArgumentException {
+ arguments = arguments.trim();
+ Date enteredDate;
+ try {
+ enteredDate = DateFormatter.stringToDate(arguments);
+ } catch (ParseException e) {
+ throw new InvalidSyntaxException("date");
+ }
+ Date currentDate = new Date();
+ if (enteredDate.compareTo(currentDate) > 0) {
+ throw new InvalidArgumentException("date");
+ }
+ return enteredDate;
+ }
+}
diff --git a/src/main/java/seedu/parser/WorkoutParser.java b/src/main/java/seedu/parser/WorkoutParser.java
new file mode 100644
index 0000000000..932c8a39b5
--- /dev/null
+++ b/src/main/java/seedu/parser/WorkoutParser.java
@@ -0,0 +1,252 @@
+package seedu.parser;
+
+import seedu.commands.Command;
+import seedu.commands.workoutcommands.AddExerciseCommand;
+import seedu.commands.workoutcommands.CountSetsRepsCommand;
+import seedu.commands.workoutcommands.DeleteWorkoutCommand;
+import seedu.commands.workoutcommands.EndWorkoutCommand;
+import seedu.commands.workoutcommands.ListWorkoutCommand;
+import seedu.commands.workoutcommands.StartWorkoutCommand;
+import seedu.commands.workoutcommands.ViewWorkoutCommand;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+import seedu.workout.Exercise;
+
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static java.lang.Math.max;
+import static seedu.parser.Parser.parseDate;
+
+/**
+ * Represents the parser for workout commands.
+ */
+public class WorkoutParser {
+ private static final int EXERCISE_NAME_INDEX = 0;
+ private static final int WEIGHT_INDEX = 1;
+ private static final int REPS_PER_SET_INDEX = 2;
+ private static final int ADD_ARGUMENT_COUNT = 3;
+
+ //@@author calebcjl
+ /**
+ * Parse arguments for /wadd command.
+ *
+ * @param arguments Arguments for add workout command.
+ * @return AddWorkoutCommand if arguments are valid.
+ * @throws InvalidSyntaxException If there is invalid syntax.
+ */
+ static Command parseAddExerciseCommand(String arguments)
+ throws InvalidSyntaxException, InvalidArgumentException {
+ String[] exerciseDetails = new String[ADD_ARGUMENT_COUNT];
+ Matcher matcher = Pattern.compile("\\d+").matcher(arguments);
+ matcher.find();
+ try {
+ exerciseDetails[EXERCISE_NAME_INDEX] = arguments.substring(0, arguments.indexOf(matcher.group()));
+ exerciseDetails[WEIGHT_INDEX] = arguments.substring(arguments.indexOf(matcher.group()),
+ max(arguments.indexOf("kg"), arguments.indexOf("lb")) + 2);
+ exerciseDetails[REPS_PER_SET_INDEX] = arguments.substring
+ (arguments.indexOf(exerciseDetails[WEIGHT_INDEX]) + exerciseDetails[WEIGHT_INDEX].length());
+ } catch (IndexOutOfBoundsException | IllegalStateException e) {
+ throw new InvalidSyntaxException("/wadd command");
+ }
+
+ String exerciseName = parseExerciseName(exerciseDetails[EXERCISE_NAME_INDEX]);
+ String weight = parseWeight(exerciseDetails[WEIGHT_INDEX]);
+ String repsPerSet = parseRepsPerSet(exerciseDetails[REPS_PER_SET_INDEX]);
+ Exercise toAdd = new Exercise(exerciseName, weight, repsPerSet);
+
+ return new AddExerciseCommand(toAdd);
+ }
+
+ //@@author calebcjl
+ /**
+ * Check if name is valid.
+ * Name is valid if it is not an empty string.
+ *
+ * @param name Name to be checked.
+ * @return True if valid. Returns false otherwise.
+ */
+ private static boolean isValidName(String name) {
+ return name != null && !name.isEmpty();
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses exercise name argument.
+ * Removes any leading and trailing whitespaces.
+ *
+ * @param exerciseName Exercise name argument.
+ * @return Exercise name.
+ * @throws InvalidArgumentException If syntax is invalid.
+ */
+ private static String parseExerciseName(String exerciseName) throws InvalidArgumentException {
+ exerciseName = exerciseName.trim();
+ if (!isValidName(exerciseName)) {
+ throw new InvalidArgumentException("exercise name");
+ }
+ return exerciseName;
+ }
+
+ //@@author calebcjl
+ /**
+ * Checks if weight is valid.
+ * A valid weight contains a positive number with at most 2 decimal place and weight unit (kg or lb).
+ *
+ * @param weight Weight to be checked.
+ * @return True if weight is valid. Returns false otherwise.
+ */
+ private static boolean isValidWeight(String weight) {
+ if (weight == null || weight.isEmpty()) {
+ return false;
+ }
+ if (!weight.contains("kg") && !weight.contains("lb")) {
+ return false;
+ }
+ try {
+ Integer.parseUnsignedInt(weight.substring(0, max(weight.indexOf("kg"), weight.indexOf("lb"))));
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses weight argument.
+ *
+ * @param weight Weight argument.
+ * @return Weight.
+ */
+ private static String parseWeight(String weight) throws InvalidArgumentException {
+ weight = weight.trim();
+ if (!isValidWeight(weight)) {
+ throw new InvalidArgumentException("weight");
+ }
+ return weight;
+ }
+
+ //@@author calebcjl
+ /**
+ * Check if reps per set are valid.
+ * A valid reps per set is a String of positive integers separated by a single whitespace.
+ *
+ * @param repsPerSet Reps per set argument.
+ * @return True if reps per set are valid. Returns false otherwise.
+ */
+ private static boolean isValidRepsPerSet(String repsPerSet) {
+ String[] reps = repsPerSet.split(" ");
+ try {
+ for (String repCount : reps) {
+ Integer.parseUnsignedInt(repCount);
+ }
+ } catch (NumberFormatException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses reps per set argument.
+ *
+ * @param repsPerSet Reps per set argument.
+ * @return Reps per set.
+ */
+ private static String parseRepsPerSet(String repsPerSet) throws InvalidArgumentException {
+ repsPerSet = repsPerSet.trim();
+ if (!isValidRepsPerSet(repsPerSet)) {
+ throw new InvalidArgumentException("reps per set");
+ }
+ return repsPerSet;
+ }
+
+ //@@author ZIZI-czh
+ /**
+ * This method is used to check the "/start" command
+ * Otherwise, StartCommand will be executed
+ *
+ * @param arguments Date input
+ * @return Incorrect command if the input date is incorrect, otherwise, initialize the StartCommand
+ */
+ static Command parseStartWorkoutCommand(String arguments) throws InvalidArgumentException {
+ Date date = new Date();
+ String workoutName = parseWorkoutName(arguments);
+ return new StartWorkoutCommand(date, workoutName);
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses workout name for StartWorkoutCommand
+ * @param workoutName Name of workout.
+ * @return Name of workout.
+ * @throws InvalidArgumentException If workout name is invalid.
+ */
+ static String parseWorkoutName(String workoutName) throws InvalidArgumentException {
+ if (workoutName.isBlank()) {
+ throw new InvalidArgumentException("workout name");
+ }
+ return workoutName.trim();
+ }
+
+ /**
+ * This method is used to check the "/delete" command
+ *
+ * @param arguments Date input
+ * @return DeleteWorkoutCommand.
+ */
+ static Command parseDeleteWorkoutCommand(String arguments) throws InvalidSyntaxException {
+ arguments = arguments.trim();
+ int index;
+ try {
+ index = Integer.parseUnsignedInt(arguments) - 1;
+ } catch (NumberFormatException e) {
+ throw new InvalidSyntaxException("/wdelete command");
+ }
+ return new DeleteWorkoutCommand(index);
+ }
+
+ //@@ author ZIZI-czh
+ static Command parseListWorkoutCommand(String arguments) throws InvalidSyntaxException {
+ if (arguments != null && !arguments.isBlank()) {
+ throw new InvalidSyntaxException("/wlist command");
+ }
+ return new ListWorkoutCommand();
+ }
+
+
+ //@@ author Richardtok
+ static Command parseViewWorkoutCommand(String arguments) throws InvalidArgumentException {
+ arguments = arguments.trim();
+ int index;
+ try {
+ index = Integer.parseUnsignedInt(arguments) - 1;
+ } catch (NumberFormatException e) {
+ throw new InvalidArgumentException("index");
+ }
+ return new ViewWorkoutCommand(index);
+ }
+
+ //@@ author guillaume-grn
+ static Command parseSetsRepsCountCommand(String arguments) throws InvalidArgumentException,
+ InvalidSyntaxException {
+ Date date = parseDate(arguments);
+ return new CountSetsRepsCommand(date);
+ }
+
+ //@@author calebcjl
+ /**
+ * Parses arguments of end workout command.
+ *
+ * @param arguments Arguments of end workout command.
+ * @return End workout command.
+ * @throws InvalidSyntaxException If syntax of command is invalid.
+ */
+ static Command parseEndWorkoutCommand(String arguments) throws InvalidSyntaxException {
+ if (arguments != null && !arguments.isBlank()) {
+ throw new InvalidSyntaxException("/wend command");
+ }
+ return new EndWorkoutCommand();
+ }
+}
diff --git a/src/main/java/seedu/storage/CalorieTrackerStorage.java b/src/main/java/seedu/storage/CalorieTrackerStorage.java
new file mode 100644
index 0000000000..e261c31dbc
--- /dev/null
+++ b/src/main/java/seedu/storage/CalorieTrackerStorage.java
@@ -0,0 +1,81 @@
+package seedu.storage;
+
+import seedu.calorietracker.Food;
+import seedu.calorietracker.FoodList;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Scanner;
+
+//@@author calebcjl
+/**
+ * Represents a storage for CalorieTracker.
+ */
+public class CalorieTrackerStorage {
+ private static final File defaultCalorieTrackerFile = new File("data/calorietracker.txt");
+ private final File calorieTrackerFile;
+ public CalorieTrackerStorage() {
+ calorieTrackerFile = defaultCalorieTrackerFile;
+ }
+
+ public HashMap getUserData() {
+ HashMap savedCalorieTracker = new HashMap<>();
+ if (calorieTrackerFile.exists()) {
+ try {
+ Scanner scanner = new Scanner(calorieTrackerFile);
+ while (scanner.hasNext()) {
+ readCalorieTrackerFile(scanner.nextLine(), savedCalorieTracker);
+ }
+ } catch (FileNotFoundException | ParseException e) {
+ Ui.showReadFileErrorMessage("calorie tracker");
+ }
+ } else {
+ Ui.showNoSavedDataMessage("calorie tracker");
+ createCalorieTrackerFile();
+ }
+ Ui.showSuccessfulLoadDataMessage("calorie tracker");
+ Ui.showOneLine();
+ return savedCalorieTracker;
+ }
+
+ private void readCalorieTrackerFile(String line, HashMap dailyFoodConsumption)
+ throws ParseException {
+ String[] data = line.split(",");
+ Date date = DateFormatter.stringToDate(data[0]);
+ FoodList foodList = new FoodList();
+ for (int i = 1; i < data.length; i += 2) {
+ Food food = new Food(data[i], Integer.parseInt(data[i + 1]));
+ foodList.addFood(food);
+ }
+ dailyFoodConsumption.put(date, foodList);
+ }
+
+ private void createCalorieTrackerFile() {
+ try {
+ if (calorieTrackerFile.createNewFile()) {
+ Ui.showCreatedNewFileMessage("calorie tracker");
+ }
+ } catch (IOException e) {
+ Ui.showNewFileNotCreatedMessage("calorie tracker");
+ }
+ }
+
+ public void saveUserData(HashMap dailyFoodConsumption) throws IOException {
+ FileWriter fileWriter = new FileWriter(calorieTrackerFile);
+ for (Date date : dailyFoodConsumption.keySet()) {
+ fileWriter.write(DateFormatter.dateToString(date) + ',');
+ for (Food food : dailyFoodConsumption.get(date).getFoods()) {
+ fileWriter.write(food.getFoodName() + ',' + food.getCalories() + ',');
+ }
+ fileWriter.write(System.lineSeparator());
+ }
+ fileWriter.close();
+ }
+}
diff --git a/src/main/java/seedu/storage/FoodDictionaryStorage.java b/src/main/java/seedu/storage/FoodDictionaryStorage.java
new file mode 100644
index 0000000000..2cd6aff135
--- /dev/null
+++ b/src/main/java/seedu/storage/FoodDictionaryStorage.java
@@ -0,0 +1,106 @@
+package seedu.storage;
+
+import seedu.ui.Ui;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Scanner;
+
+//@@author ZIZI-czh
+
+/**
+ * Represents a storage for FoodDictionary.
+ */
+public class FoodDictionaryStorage {
+ private static final File defaultFoodDictionaryFile = new File("data/fooddict.txt");
+ private final File foodDictionaryFile;
+
+ public FoodDictionaryStorage() {
+ foodDictionaryFile = defaultFoodDictionaryFile;
+ }
+
+
+ //@@author ZIZI-czh
+
+ /**
+ * Retrieves the saved user food dictionary data from a file and returns it as a HashMap.
+ * If the file exists, reads the file line by line and adds the key-value pairs to the HashMap.
+ * If the file does not exist, creates a new file and displays a message to the user.
+ * If an error occurs while reading the file, displays an error message to the user.
+ * After retrieving the data, displays a success message to the user.
+ *
+ * @return A HashMap representing the saved user food dictionary data.
+ */
+ public HashMap getUserData() {
+ HashMap savedFoodDictionary = new HashMap<>();
+ if (foodDictionaryFile.exists()) {
+ try {
+ Scanner scanner = new Scanner(foodDictionaryFile);
+ while (scanner.hasNext()) {
+ readFoodDictionaryFileLine(scanner.nextLine(), savedFoodDictionary);
+ }
+ } catch (FileNotFoundException e) {
+ Ui.showReadFileErrorMessage("food dictionary");
+ }
+ } else {
+ Ui.showNoSavedDataMessage("food dictionary");
+ createFoodDictionaryFile();
+ }
+ Ui.showSuccessfulLoadDataMessage("food dictionary");
+ Ui.showOneLine();
+ return savedFoodDictionary;
+ }
+
+ //@@author ZIZI-czh
+
+ /**
+ * Reads a single line from the food dictionary file and extracts the name and calorie count of a food item.
+ * The extracted data is added to the provided hashmap of saved food items.
+ *
+ * @param line the line to read and extract data from
+ * @param savedFoodDictionary the hashmap to add the extracted food item data to
+ */
+ private void readFoodDictionaryFileLine(String line, HashMap savedFoodDictionary) {
+ String[] data = line.split(":");
+ savedFoodDictionary.put(data[0], Integer.valueOf(data[1]));
+ }
+
+ //@@author ZIZI-czh
+
+ /**
+ * Creates a new file for the food dictionary if it doesn't exist.
+ * If the file already exists, does nothing.
+ * If the creation is successful, displays a success message to the user.
+ * If the creation fails, displays an error message to the user.
+ */
+ private void createFoodDictionaryFile() {
+ try {
+ if (foodDictionaryFile.createNewFile()) {
+ Ui.showCreatedNewFileMessage("food dictionary");
+ }
+ } catch (IOException e) {
+ Ui.showNewFileNotCreatedMessage("food dictionary");
+ }
+ }
+
+ //@@author ZIZI-czh
+
+ /**
+ * Saves the given HashMap of food names and calorie counts to the food dictionary file. Each line of the file
+ * contains a food name followed by a colon and the corresponding calorie count. The file is created if it doesn't
+ * exist. If the file already exists, it is overwritten with the new data.
+ *
+ * @param foodCalories a HashMap that maps food names to their respective calorie counts
+ * @throws IOException if there is an error writing to the file
+ */
+ public void saveUserData(HashMap foodCalories) throws IOException {
+ FileWriter fileWriter = new FileWriter(foodDictionaryFile);
+ for (String foodName : foodCalories.keySet()) {
+ fileWriter.write(foodName + ':' + foodCalories.get(foodName) + System.lineSeparator());
+ }
+ fileWriter.close();
+ }
+}
diff --git a/src/main/java/seedu/storage/Storage.java b/src/main/java/seedu/storage/Storage.java
new file mode 100644
index 0000000000..5fcf39adc4
--- /dev/null
+++ b/src/main/java/seedu/storage/Storage.java
@@ -0,0 +1,65 @@
+package seedu.storage;
+
+import seedu.calorietracker.CalorieTracker;
+import seedu.calorietracker.FoodDictionary;
+import seedu.calorietracker.FoodList;
+import seedu.ui.Ui;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+//@@author calebcjl
+/**
+ * Represents the main storage for all storage classes.
+ */
+public class Storage {
+ private final WorkoutListStorage workoutListStorage;
+ private final FoodDictionaryStorage foodDictionaryStorage;
+ private final CalorieTrackerStorage calorieTrackerStorage;
+
+ public Storage() {
+ workoutListStorage = new WorkoutListStorage();
+ foodDictionaryStorage = new FoodDictionaryStorage();
+ calorieTrackerStorage = new CalorieTrackerStorage();
+ }
+
+ /**
+ * Returns list of workouts saved in user data file.
+ *
+ * @return List of workouts.
+ */
+ public ArrayList readWorkoutListFile() {
+ return workoutListStorage.getUserData();
+ }
+
+ /**
+ * Returns food list saved in user data file.
+ *
+ * @return Food list.
+ */
+ public HashMap readFoodDictionaryFile() {
+ return foodDictionaryStorage.getUserData();
+ }
+
+ /**
+ * Returns calorie tracker saved in user data file.
+ *
+ * @return Calorie tracker.
+ */
+ public HashMap readCalorieTrackerFile() {
+ return calorieTrackerStorage.getUserData();
+ }
+ public void saveUserData(WorkoutList workoutList, FoodDictionary foodDictionary, CalorieTracker calorieTracker) {
+ try {
+ workoutListStorage.saveUserData(workoutList.getWorkouts());
+ foodDictionaryStorage.saveUserData(foodDictionary.getFoodCalories());
+ calorieTrackerStorage.saveUserData(calorieTracker.getDailyFoodConsumption());
+ } catch (IOException e) {
+ Ui.showSaveUserDataErrorMessage();
+ }
+ }
+}
diff --git a/src/main/java/seedu/storage/WorkoutListStorage.java b/src/main/java/seedu/storage/WorkoutListStorage.java
new file mode 100644
index 0000000000..e84aaddc23
--- /dev/null
+++ b/src/main/java/seedu/storage/WorkoutListStorage.java
@@ -0,0 +1,125 @@
+package seedu.storage;
+
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+//@@author ZIZI-czh
+/**
+ * Represents a storage for WorkoutList.
+ */
+public class WorkoutListStorage {
+ private static final File defaultWorkoutListFile = new File("data/workoutlist.txt");
+ private final File workoutListFile;
+
+
+
+ public WorkoutListStorage() {
+ workoutListFile = defaultWorkoutListFile;
+ }
+
+
+ //@@author ZIZI-czh
+ /**
+ * Retrieves the saved workout data from the workout list file and returns an ArrayList of Workout objects.
+ * If the workout list file does not exist, the method shows a message to the user and creates the file.
+ * If there is an error reading the file, the method shows an error message to the user.
+ * The method also shows a successful message to the user indicating that the workout data has been loaded.
+ *
+ * @return An ArrayList of Workout objects containing the saved workout data.
+ */
+ public ArrayList getUserData() {
+ ArrayList savedWorkoutList = new ArrayList<>();
+ if (workoutListFile.exists()) {
+ try {
+ Scanner scanner = new Scanner(workoutListFile);
+ while (scanner.hasNext()) {
+ readWorkoutListFileLine(scanner.nextLine(), savedWorkoutList);
+ }
+ } catch (FileNotFoundException | ParseException e) {
+ Ui.showReadFileErrorMessage("workout list file");
+ }
+ } else {
+ Ui.showNoSavedDataMessage("workout list");
+ createWorkoutListFile();
+ }
+ Ui.showSuccessfulLoadDataMessage("workout list");
+ Ui.showOneLine();
+ return savedWorkoutList;
+ }
+
+ //@@author ZIZI-czh
+ /**
+ * Reads a single line from the workout list file and creates a Workout object from the data.
+ * The Workout object is then added to the given ArrayList of Workout objects.
+ *
+ * @param line A String representing a single line of data from the workout list file.
+ * @param savedWorkoutList An ArrayList of Workout objects where the resulting Workout object will be added.
+ * @throws ParseException If there is an error parsing the date from the line of data.
+ */
+ private void readWorkoutListFileLine(String line, ArrayList savedWorkoutList) throws ParseException {
+ String[] data = line.split(",");
+ Workout workout = new Workout(DateFormatter.stringToDate(data[0]), data[1]);
+ for (int i = 2; i < data.length - 2; i += 3) {
+ Exercise exercise = new Exercise(data[i], data[i + 1], data[i + 2]);
+ workout.addExercise(exercise);
+ }
+ savedWorkoutList.add(workout);
+ }
+
+
+ //@@author ZIZI-czh
+ /**
+ * Creates a new workout list file and displays appropriate messages to the user based on
+ * whether the directory and file were created successfully or not.
+ * If the directory was created successfully, a success message is displayed to the user.
+ * If the directory was not created successfully, an error message is displayed to the user.
+ * If the file was created successfully, a success message is displayed to the user.
+ * If the file was not created successfully, an error message is displayed to the user.
+ */
+ private void createWorkoutListFile() {
+ try {
+ if (workoutListFile.getParentFile().mkdirs()) {
+ Ui.showCreateDirectoryMessage();
+ } else {
+ Ui.showDirectoryNotCreatedMessage();
+ }
+ if (workoutListFile.createNewFile()) {
+ Ui.showCreatedNewFileMessage("workout list");
+ }
+ } catch (IOException e) {
+ Ui.showNewFileNotCreatedMessage("workout list");
+ }
+ }
+
+
+ //@@author ZIZI-czh
+ /**
+ * Saves the list of workouts to the workout list file.
+ *
+ * @param workouts the list of workouts to be saved
+ * @throws IOException if an I/O error occurs while writing to the file
+ */
+ public void saveUserData(ArrayList workouts) throws IOException {
+ FileWriter fileWriter = new FileWriter(workoutListFile);
+ for (Workout workout : workouts) {
+ fileWriter.write(DateFormatter.dateToString(workout.getDate()) + ','
+ + workout.getWorkoutName() + ',');
+ for (Exercise exercise : workout.getExercises()) {
+ fileWriter.write(exercise.getName() + ',' + exercise.getWeight() + ','
+ + exercise.getRepsPerSet() + ',');
+ }
+ fileWriter.write(System.lineSeparator());
+ }
+ fileWriter.close();
+ }
+}
diff --git a/src/main/java/seedu/ui/Ui.java b/src/main/java/seedu/ui/Ui.java
new file mode 100644
index 0000000000..cfd623c247
--- /dev/null
+++ b/src/main/java/seedu/ui/Ui.java
@@ -0,0 +1,131 @@
+package seedu.ui;
+
+import seedu.commands.Command;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+
+import java.util.Scanner;
+
+public class Ui {
+ private static final String LINE = "=======================================";
+ private static final String LINE_SEPARATOR = "----------------------------------------";
+
+ private static final String WELCOME_MESSAGE = "Welcome to FITZ! Time to record your " +
+ "daily workouts and calories consumption!\n"
+ + "Enter \"/whelp\" "
+ + "if you need the list of commands for workouts record.\n"
+ + "Enter \"/chelp\" "
+ + "if you need the list of commands for calories record.\n"
+ + LINE_SEPARATOR;
+ private static final String LOGO_MESSAGE = " _______ __ .___________.________ \n" +
+ "| ____|| | | | / \n" +
+ "| |__ | | `---| |----`---/ / \n" +
+ "| __| | | | | / / \n" +
+ "| | | | | | / /----.\n" +
+ "|__| |__| |__| /________|";
+ private static final Scanner in = new Scanner(System.in);
+ //@@ author RIchardtok
+ private static final String HELP_MESSAGE_WORKOUT =
+ "Here are the list of commands that you can use for workout record:"
+ +System.lineSeparator() + LINE + System.lineSeparator()
+ + "- [Start a workout: /wstart EXERCISE_NAME])" + System.lineSeparator()
+ + "- [Add exercise: /wadd EXERCISE_NAME WEIGHT_USED_WEIGHT_UNIT RPS]" + System.lineSeparator()
+ + "- [Start a workout: /wstart])" + System.lineSeparator()
+ + "- [Add exercise: /wadd]" + System.lineSeparator()
+ + "- [Display all the days: /wlist]" + System.lineSeparator()
+ + "- [Display workouts information for a specific day: /wview INDEX]" + System.lineSeparator()
+ + "- [Display total amount of reps and set for one week /wcount DD/MM/YY]" + System.lineSeparator()
+ + "- [Delete workouts: /wdelete INDEX]" + System.lineSeparator()
+ + "- [End current workout: /wend]" + System.lineSeparator() + LINE
+ + "- [Exit app: /exit]" + System.lineSeparator() + LINE;
+ private static final String HELP_MESSAGE_CALORIES =
+ "Here are the list of commands that you can use for calories record:"
+ +System.lineSeparator() + LINE + System.lineSeparator()
+ + "- [Add food and calories: /cadd DD/MM/YY]" + System.lineSeparator()
+ + "- [Display total calories consumption: /clist]" + System.lineSeparator()
+ + "- [Display calories consumed on a specific date : /cview DD/MM/YY]" + System.lineSeparator()
+ + "- [Delete calories record for one food: /cdelete DD/MM/YY]"
+ + System.lineSeparator() + LINE + System.lineSeparator();
+ private static final String READ_FILE_ERROR_MESSAGE = "Error reading file: ";
+ public static void showGreeting() {
+ System.out.println(WELCOME_MESSAGE);
+ }
+
+ public static void showLogo(){
+ System.out.println(LOGO_MESSAGE);
+ }
+
+ public static void showOneLine(){
+ System.out.println(LINE);
+ }
+
+
+ public static String line() {
+ return LINE;
+ }
+
+ public static String getUserInput() {
+ return in.nextLine();
+ }
+
+ public static void showWelcomeMessage() {
+ showOneLine();
+ showLogo();
+ showOneLine();
+ showGreeting();
+ }
+
+ public static String getWorkoutHelpMessage() {
+ return HELP_MESSAGE_WORKOUT;
+ }
+
+ public static void showErrorMessage(String errorMessage) {
+ System.out.println(errorMessage);
+ }
+
+ public static void showCommandResult(Command command)
+ throws InvalidArgumentException, InvalidSyntaxException {
+ System.out.println(command.execute());
+ }
+
+ public static void showReadFileErrorMessage(String fileName) {
+ System.out.println(READ_FILE_ERROR_MESSAGE + fileName);
+ }
+
+ public static void showNoSavedDataMessage(String fileName) {
+ System.out.println("No saved data found for " + fileName + '.');
+ System.out.println("Creating new file for " + fileName + ".......");
+ }
+
+ public static void showCreatedNewFileMessage(String fileName) {
+ System.out.println("New file for " + fileName + " created.");
+ }
+ public static void showNewFileNotCreatedMessage(String fileName) {
+ System.out.println("Error creating new file for " + fileName + ".");
+ System.out.println("User data may not be saved!");
+ }
+
+ public static void showCreateDirectoryMessage() {
+ System.out.println("Creating directories.....");
+ }
+
+ public static void showDirectoryNotCreatedMessage() {
+ System.out.println("Unable to create directories. User data may not be saved.");
+ }
+
+ public static void showSaveUserDataErrorMessage() {
+ System.out.println("Error saving user data.");
+ }
+ public static void showSuccessfulLoadDataMessage(String fileName) {
+ System.out.println("Successfully loaded " + fileName + " data.");
+ }
+
+ public static String getCaloriesHelpMessage() {
+ return HELP_MESSAGE_CALORIES;
+ }
+
+ public static void setInput(String userInput) {
+
+ }
+
+}
diff --git a/src/main/java/seedu/workout/Exercise.java b/src/main/java/seedu/workout/Exercise.java
new file mode 100644
index 0000000000..e2014d1202
--- /dev/null
+++ b/src/main/java/seedu/workout/Exercise.java
@@ -0,0 +1,68 @@
+package seedu.workout;
+
+//@@author calebcjl
+/**
+ * Represents an exercise. It stores the name, weight used and the number of sets and reps.
+ */
+public class Exercise {
+ private final String name;
+ private final String weight;
+ private final String repsPerSet;
+
+ public Exercise(String name, String weight, String repsPerSet) {
+ this.name = name;
+ this.weight = weight;
+ this.repsPerSet = repsPerSet;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getWeight() {
+ return weight;
+ }
+
+ public String getRepsPerSet() {
+ return repsPerSet;
+ }
+
+ @Override
+ public String toString() {
+ return name + ' ' + weight + ' ' + repsPerSet;
+ }
+
+ //@@author guillaume-grn
+ /**
+ * Returns the number of sets for the exercise.
+ *
+ * @return the number of sets for the exercise
+ */
+ public int getSetsCount() {
+ String repsPerSet = this.repsPerSet;
+ String[] sets = repsPerSet.split(" ");
+ return sets.length;
+ }
+
+ //@@author guillaume-grn
+ /**
+ * Returns the total number of reps for the exercise.
+ *
+ * @return the total number of reps for the exercise
+ */
+ public int getRepsCount() {
+ String repsPerSet = this.repsPerSet;
+ String[] sets = repsPerSet.split(" ");
+ int totalReps = 0;
+ for (String set : sets) {
+ try {
+ totalReps += Integer.parseInt(set);
+ } catch (NumberFormatException e) {
+ System.out.println("Invalid reps format:" + repsPerSet);
+ return 0;
+ }
+ }
+ return totalReps;
+ }
+
+}
diff --git a/src/main/java/seedu/workout/Workout.java b/src/main/java/seedu/workout/Workout.java
new file mode 100644
index 0000000000..23b30920b3
--- /dev/null
+++ b/src/main/java/seedu/workout/Workout.java
@@ -0,0 +1,75 @@
+package seedu.workout;
+
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+import java.util.ArrayList;
+import java.util.Date;
+
+
+/**
+ * Represents a workout. It stores the date, name and list of exercises of the workout.
+ */
+public class Workout {
+ private Date date;
+ private String workoutName;
+ private final ArrayList exercises;
+
+ //@@author ZIZI-czh
+ public Workout() {
+ exercises = new ArrayList<>();
+ }
+
+ //@@author ZIZI-czh
+ /**
+ * Creates a new Workout object with the given date and workout name.
+ * Initializes the exercises list to an empty ArrayList.
+ *
+ * @param date the date of the workout
+ * @param workoutName the name of the workout
+ */
+ public Workout(Date date, String workoutName) {
+ this.date = date;
+ this.workoutName = workoutName;
+ exercises = new ArrayList<>();
+ }
+
+
+ //@@author ZIZI-czh
+ public String getWorkoutName() {
+ return workoutName;
+ }
+
+ //@@author ZIZI-czh
+ public Date getDate() {
+ return date;
+ }
+
+ //@@author ZIZI-czh
+ public ArrayList getExercises() {
+ return exercises;
+ }
+
+ public void addExercise(Exercise exercise) {
+ exercises.add(exercise);
+ }
+
+ //@@author calebcjl
+ /**
+ * Returns the list of exercises in the workout.
+ *
+ * @return List of exercises.
+ */
+ @Override
+ public String toString() {
+ String header = "Here are the list of exercises for " + getWorkoutName() + " on "
+ + DateFormatter.dateToString(date) + '.' + System.lineSeparator();
+ StringBuilder exercisesList = new StringBuilder(header);
+ int counter = 1;
+ for (Exercise exercise : exercises) {
+ exercisesList.append(counter).append(". ").append(exercise.toString()).append(System.lineSeparator());
+ counter += 1;
+ }
+ return exercisesList.append(Ui.line()).toString();
+ }
+}
+
diff --git a/src/main/java/seedu/workout/WorkoutList.java b/src/main/java/seedu/workout/WorkoutList.java
new file mode 100644
index 0000000000..f0140d69e0
--- /dev/null
+++ b/src/main/java/seedu/workout/WorkoutList.java
@@ -0,0 +1,208 @@
+package seedu.workout;
+
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+import seedu.storage.Storage;
+import seedu.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+
+//@@author calebcjl
+public class WorkoutList {
+ public static final String EMPTY_WORKOUT = "There are no workouts reported during this week !";
+ public static final String INFORMATION = "Information of exercises for the week of ";
+ public static final int NO_CURRENT_WORKOUT = -1;
+ private final ArrayList workouts;
+ private int currentWorkoutIndex;
+
+ public WorkoutList() {
+ workouts = new ArrayList<>();
+ currentWorkoutIndex = NO_CURRENT_WORKOUT;
+ }
+
+ public WorkoutList(Storage storage) {
+ workouts = storage.readWorkoutListFile();
+ currentWorkoutIndex = NO_CURRENT_WORKOUT;
+ }
+
+
+ //@@author ZIZI-czh
+ //this method is used for JunitTest
+ public WorkoutList(ArrayList workouts) {
+ this.workouts = workouts;
+ currentWorkoutIndex = NO_CURRENT_WORKOUT;
+ }
+
+
+ public int getCurrentWorkoutIndex() {
+ return currentWorkoutIndex;
+ }
+
+ public void setCurrentWorkoutIndex(int currentWorkoutIndex) {
+ this.currentWorkoutIndex = currentWorkoutIndex;
+ }
+
+ public ArrayList getWorkouts() {
+ return workouts;
+ }
+
+ //@@author guillaume-grn
+ /**
+ * Counts the number of sets and reps for each exercise in a specific week.
+ *
+ * @param dateInSpecificWeek Date in the specific week.
+ * @return String representation of the number of sets and reps for each exercise in the specific week.
+ */
+ public String countSetsReps(Date dateInSpecificWeek) {
+ ArrayList workoutsInSpecificWeek = getWorkoutsInSpecificWeek(dateInSpecificWeek);
+ HashMap> distinctExercises = new HashMap<>();
+ for (Workout workout : workoutsInSpecificWeek) {
+ for (Exercise exercise : workout.getExercises()) {
+ ArrayList setsAndReps = new ArrayList<>();
+ int sets = exercise.getSetsCount();
+ int reps = exercise.getRepsCount();
+ if (distinctExercises.containsKey(exercise.getName())) {
+ sets += distinctExercises.get(exercise.getName()).get(0);
+ reps += distinctExercises.get(exercise.getName()).get(1);
+ }
+ setsAndReps.add(sets);
+ setsAndReps.add(reps);
+ distinctExercises.put(exercise.getName(), setsAndReps);
+ }
+ }
+ return displayCountSetsReps(distinctExercises, dateInSpecificWeek);
+ }
+
+ /**
+ * Displays the count of sets and reps for each distinct exercise performed in a specific week.
+ *
+ * @param distinctExercises A HashMap containing distinct exercises names as keys and an ArrayList
+ * of sets and reps as values.
+ * @param dateInSpecificWeek Date representing a specific week to display count of sets and reps.
+ * @return A String representation of the count of sets and reps for each distinct exercise performed
+ * in the specific week.
+ */
+ //@@ author ZIZI-czh
+ public static String displayCountSetsReps(HashMap> distinctExercises,
+ Date dateInSpecificWeek) {
+ if (distinctExercises.isEmpty()) {
+ return EMPTY_WORKOUT;
+ }
+
+ StringBuilder output = new StringBuilder();
+ output.append(INFORMATION)
+ .append(DateFormatter.dateToString(dateInSpecificWeek))
+ .append(System.lineSeparator());
+ for (String exerciseName : distinctExercises.keySet()) {
+ output.append("Name: ")
+ .append(exerciseName)
+ .append(", sets: ")
+ .append(distinctExercises.get(exerciseName).get(0))
+ .append(", rps: ")
+ .append(distinctExercises.get(exerciseName).get(1))
+ .append(System.lineSeparator());
+ }
+ return output + Ui.line();
+ }
+
+ //@@author guillaume-grn
+ /**
+ * Returns a list of workouts that occurred within a specific week.
+ *
+ * @param dayInSpecificWeekDate Date representing a specific day in a week to get workouts from.
+ * @return ArrayList of Workout objects that occurred within the specified week.
+ */
+ public ArrayList getWorkoutsInSpecificWeek(Date dayInSpecificWeekDate) {
+ ArrayList workoutsInSpecificWeek = new ArrayList<>();
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(dayInSpecificWeekDate);
+ calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
+ Date startOfWeekDate = calendar.getTime(); //Monday of the specific week
+ calendar.add(Calendar.DAY_OF_WEEK, 6);
+ Date endOfWeekDate = calendar.getTime(); //Sunday of the specified week
+ for (Workout workout : workouts) {
+ if (workout.getDate().compareTo(startOfWeekDate) >= 0 && workout.getDate().compareTo(endOfWeekDate) <= 0 ) {
+ workoutsInSpecificWeek.add(workout);
+ }
+ }
+ return workoutsInSpecificWeek;
+ }
+
+ //@@author calebcjl
+ /**
+ * Start a new workout and adds it to the workout list.
+ *
+ * @param date Date of workout.
+ * @param workoutName Name of workout.
+ * @throws InvalidArgumentException If there is a workout with the same date and name already in the list.
+ */
+ public void startWorkout(Date date, String workoutName) throws InvalidArgumentException {
+ Workout workout = new Workout(date, workoutName);
+ if (isInlist(workout)) {
+ throw new InvalidArgumentException("Workout already exist!");
+ }
+ workouts.add(workout);
+ currentWorkoutIndex = workouts.size() - 1;
+ }
+
+ //@@author calebcjl
+ /**
+ * Checks if a workout is in the workout list.
+ *
+ * @param toCheck Workout to check.
+ * @return True if workout found in list. Returns false otherwise.
+ */
+ private boolean isInlist(Workout toCheck) {
+ for (Workout workout: workouts) {
+ if (workout.getDate().equals(toCheck.getDate())
+ && workout.getWorkoutName().equals(toCheck.getWorkoutName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //@@author calebcjl
+ /**
+ * Checks if workout list is empty.
+ *
+ * @return True if empty. Returns false otherwise.
+ */
+ public boolean isEmptyList() {
+ return workouts.isEmpty();
+ }
+
+ //@@author calebcjl
+ /**
+ * Returns workout at a specified index of the workout list.
+ *
+ * @param index Index of Workout.
+ * @return Returns Workout at workoutIndex.
+ */
+ public Workout getWorkout(int index) {
+ return workouts.get(index);
+ }
+
+ //@@author calebcjl
+ /**
+ * Removes workout at a specified index of the workout list.
+ *
+ * @param index Index of workout.
+ */
+ public void deleteWorkout(int index) {
+ workouts.remove(index);
+ }
+
+ //@@author calebcjl
+ /**
+ * Returns current workout.
+ * @return Workout at current workout index.
+ */
+ public Workout getCurrentWorkout() {
+ return workouts.get(currentWorkoutIndex);
+ }
+}
+
diff --git a/src/test/java/seedu/DukeTest.java b/src/test/java/seedu/DukeTest.java
new file mode 100644
index 0000000000..a94f013f2a
--- /dev/null
+++ b/src/test/java/seedu/DukeTest.java
@@ -0,0 +1,43 @@
+package seedu;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.commands.ExitCommand;
+import seedu.ui.Ui;
+
+public class DukeTest {
+ private Duke duke;
+
+ @BeforeEach
+ public void setUp() {
+ duke = new Duke();
+ }
+
+ @Test
+ public void testDukeConstructor() {
+ try {
+ Duke.class.getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ fail("Failed to instantiate Duke object");
+ }
+ }
+
+ @Test
+ public void testIsExit() {
+ assertTrue(ExitCommand.isExit(new ExitCommand()));
+ }
+
+ @Test
+ public void testExitCommand() {
+ String expected = "Thank you, hope you had a great workout!!!"
+ + System.lineSeparator()
+ + Ui.line();
+ String actual = new ExitCommand().execute();
+ assertEquals(expected, actual);
+ }
+}
diff --git a/src/test/java/seedu/commands/ExitCommandTest.java b/src/test/java/seedu/commands/ExitCommandTest.java
new file mode 100644
index 0000000000..4a0283f877
--- /dev/null
+++ b/src/test/java/seedu/commands/ExitCommandTest.java
@@ -0,0 +1,24 @@
+package seedu.commands;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+//@@author ZIZI-czh
+public class ExitCommandTest {
+ @Test
+ public void testIsExit() {
+ ExitCommand exitCommand = new ExitCommand();
+ assertTrue(ExitCommand.isExit(exitCommand));
+ }
+
+ @Test
+ public void testExecute() {
+ ExitCommand exitCommand = new ExitCommand();
+ String expected = "Thank you, hope you had a great workout!!!"
+ + System.lineSeparator() + "=======================================";
+ assertEquals(expected, exitCommand.execute());
+ }
+
+}
diff --git a/src/test/java/seedu/commands/workoutcommands/AddWorkoutCommandTest.java b/src/test/java/seedu/commands/workoutcommands/AddWorkoutCommandTest.java
new file mode 100644
index 0000000000..f891d6a232
--- /dev/null
+++ b/src/test/java/seedu/commands/workoutcommands/AddWorkoutCommandTest.java
@@ -0,0 +1,37 @@
+package seedu.commands.workoutcommands;
+
+
+import org.junit.jupiter.api.Test;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+//@@ author ZIZI-czh
+public class AddWorkoutCommandTest {
+ private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
+ private static final Date date;
+
+ static {
+ try {
+ date = dateFormat.parse("10/11/22");
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ //@@ author ZIZI-czh
+ private static final Workout currentWorkout = new Workout();
+
+ @Test
+ public void testAddCommand() {
+ Exercise toAdd = new Exercise("Bench Press", "100kg", "5 5 4 3");
+ currentWorkout.addExercise(toAdd);
+ assertEquals(toAdd, currentWorkout.getExercises().get(0));
+ }
+}
diff --git a/src/test/java/seedu/commands/workoutcommands/DeleteWorkoutCommandTest.java b/src/test/java/seedu/commands/workoutcommands/DeleteWorkoutCommandTest.java
new file mode 100644
index 0000000000..9b5e1266f0
--- /dev/null
+++ b/src/test/java/seedu/commands/workoutcommands/DeleteWorkoutCommandTest.java
@@ -0,0 +1,37 @@
+package seedu.commands.workoutcommands;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+//@@author ZIZI-czh
+public class DeleteWorkoutCommandTest {
+
+ @Test
+ public void testDeleteWorkoutCommand() throws InvalidArgumentException, ParseException {
+ ArrayList workouts = new ArrayList<>();
+ Date date = DateFormatter.stringToDate("01/01/22");
+ Workout workout = new Workout(date, "Workout 1");
+ Exercise exercise1 = new Exercise("Push-ups", "20kg", "3 5 5");
+ Exercise exercise2 = new Exercise("Sit-ups", "5kg", "3 10");
+ workout.addExercise(exercise1);
+ workout.addExercise(exercise2);
+ workouts.add(workout);
+ WorkoutList workoutList = new WorkoutList(workouts);
+ DeleteWorkoutCommand deleteWorkoutCommand = new DeleteWorkoutCommand(workoutList, 0);
+ String expectedOutput = "Deleted Workout 1 on 01/01/22.";
+ assertEquals(expectedOutput, deleteWorkoutCommand.execute());
+ }
+}
+
+
+
+
diff --git a/src/test/java/seedu/commands/workoutcommands/ListWorkoutCommandTest.java b/src/test/java/seedu/commands/workoutcommands/ListWorkoutCommandTest.java
new file mode 100644
index 0000000000..d2393815b2
--- /dev/null
+++ b/src/test/java/seedu/commands/workoutcommands/ListWorkoutCommandTest.java
@@ -0,0 +1,64 @@
+package seedu.commands.workoutcommands;
+
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+
+//@@author ZIZI-czh
+public class ListWorkoutCommandTest {
+
+ private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+ private final SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HHmm");
+ private ListWorkoutCommand listWorkoutCommand;
+
+ @BeforeEach
+ public void setUp() {
+ System.setOut(new PrintStream(output));
+ WorkoutList workoutList = new WorkoutList();
+ listWorkoutCommand = new ListWorkoutCommand(workoutList);
+ }
+
+ @Test
+ public void execute_emptyList() {
+ String expectedOutput = "Workout list is empty";
+ assertEquals(expectedOutput, listWorkoutCommand.execute());
+ }
+
+ @Test
+ public void execute_oneWorkoutInList_listOfOneWorkout() throws ParseException, InvalidArgumentException {
+ ArrayList workouts = new ArrayList<>();
+ Date date = DateFormatter.stringToDate("01/01/2022");
+ Workout workout = new Workout(date, "Workout 1");
+ Exercise exercise1 = new Exercise("Push-ups", "20kg", "3 5 5");
+ Exercise exercise2 = new Exercise("Sit-ups", "5kg", "3 10");
+ workout.addExercise(exercise1);
+ workout.addExercise(exercise2);
+ workouts.add(workout);
+ WorkoutList workoutList = new WorkoutList(workouts);
+ listWorkoutCommand = new ListWorkoutCommand(workoutList);
+ assertFalse(workoutList.isEmptyList());
+
+ String expectedOutput = "Here is the list of dates of your workouts:" + System.lineSeparator()
+ + "1. 01/01/22 Workout 1" + System.lineSeparator()
+ + "=======================================";
+ assertEquals(expectedOutput, listWorkoutCommand.execute());
+ }
+
+
+
+}
diff --git a/src/test/java/seedu/commands/workoutcommands/StartWorkoutCommandTest.java b/src/test/java/seedu/commands/workoutcommands/StartWorkoutCommandTest.java
new file mode 100644
index 0000000000..f8939c1f70
--- /dev/null
+++ b/src/test/java/seedu/commands/workoutcommands/StartWorkoutCommandTest.java
@@ -0,0 +1,58 @@
+package seedu.commands.workoutcommands;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+//@@author ZIZI-czh
+public class StartWorkoutCommandTest {
+ private static final String DEFAULT_WORKOUT_NAME = "Test workout";
+ private WorkoutList workoutList;
+
+ @Test
+ public void startWorkout_validWorkout_success() {
+ // Set up
+ workoutList = new WorkoutList();
+ Date today = new Date();
+ String workoutName = DEFAULT_WORKOUT_NAME;
+
+ // Exercise
+ try {
+ workoutList.startWorkout(today, workoutName);
+ } catch (InvalidArgumentException e) {
+ // Should not reach here
+ assertEquals(1, 0);
+ }
+
+ // Assert
+ Workout createdWorkout = workoutList.getWorkouts().get(0);
+ assertEquals(today, createdWorkout.getDate());
+ assertEquals(workoutName, createdWorkout.getWorkoutName());
+ }
+
+ @Test
+ public void startWorkout_workoutAlreadyExists_exceptionThrown() {
+ // Set up
+ workoutList = new WorkoutList();
+ Date today = new Date();
+ String workoutName = DEFAULT_WORKOUT_NAME;
+ try {
+ workoutList.startWorkout(today, workoutName);
+ } catch (InvalidArgumentException e) {
+ // Should not reach here
+ assertEquals(1, 0);
+ }
+
+ // Exercise and assert
+ assertThrows(InvalidArgumentException.class, () -> workoutList.startWorkout(today, workoutName));
+ }
+
+}
+
diff --git a/src/test/java/seedu/commands/workoutcommands/ViewWorkoutCommandTest.java b/src/test/java/seedu/commands/workoutcommands/ViewWorkoutCommandTest.java
new file mode 100644
index 0000000000..12c7391e9c
--- /dev/null
+++ b/src/test/java/seedu/commands/workoutcommands/ViewWorkoutCommandTest.java
@@ -0,0 +1,59 @@
+package seedu.commands.workoutcommands;
+
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.parser.DateFormatter;
+import seedu.workout.Exercise;
+import seedu.workout.Workout;
+import seedu.workout.WorkoutList;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+//@@author ZIZI-czh
+public class ViewWorkoutCommandTest {
+ private WorkoutList workoutList;
+ private ViewWorkoutCommand viewWorkoutCommand;
+
+ @BeforeEach
+ public void setUp() {
+ workoutList = new WorkoutList();
+ viewWorkoutCommand = new ViewWorkoutCommand(0);
+ }
+
+ @Test
+ public void execute_validIndex_returnsCorrectString() throws InvalidArgumentException, ParseException {
+ ArrayList workouts = new ArrayList<>();
+ Date date = DateFormatter.stringToDate("01/01/2022");
+ Workout workout = new Workout(date, "Workout 1");
+ Exercise exercise1 = new Exercise("Push-ups", "20kg", "3 5 5");
+ Exercise exercise2 = new Exercise("Sit-ups", "5kg", "3 10");
+ workout.addExercise(exercise1);
+ workout.addExercise(exercise2);
+ workouts.add(workout);
+ WorkoutList workoutList = new WorkoutList(workouts);
+ viewWorkoutCommand = new ViewWorkoutCommand(workoutList, 0);
+ String expectedOutput = "Here are the list of exercises for " + workouts.get(0).getWorkoutName()
+ + " on " + DateFormatter.dateToString(date) + "."
+ + System.lineSeparator()
+ + "1. Push-ups 20kg 3 5 5"
+ + System.lineSeparator()
+ + "2. Sit-ups 5kg 3 10"
+ + System.lineSeparator()
+ + "=======================================";
+ assertEquals(expectedOutput, viewWorkoutCommand.execute());
+ }
+
+ @Test
+ public void execute_invalidIndex_throwsInvalidArgumentException() {
+ viewWorkoutCommand = new ViewWorkoutCommand(workoutList, 0);
+ assertThrows(InvalidArgumentException.class, () -> viewWorkoutCommand.execute());
+ }
+}
diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java
deleted file mode 100644
index 2dda5fd651..0000000000
--- a/src/test/java/seedu/duke/DukeTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package seedu.duke;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-class DukeTest {
- @Test
- public void sampleTest() {
- assertTrue(true);
- }
-}
diff --git a/src/test/java/seedu/parser/CalorieParserTest.java b/src/test/java/seedu/parser/CalorieParserTest.java
new file mode 100644
index 0000000000..173f157982
--- /dev/null
+++ b/src/test/java/seedu/parser/CalorieParserTest.java
@@ -0,0 +1,42 @@
+package seedu.parser;
+
+import org.junit.jupiter.api.Test;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+
+import static org.junit.Assert.assertThrows;
+import static seedu.parser.CalorieParser.parseAddCalorieCommand;
+import static seedu.parser.CalorieParser.parseDeleteCalorieCommand;
+import static seedu.parser.CalorieParser.parseListCalorieCommand;
+
+class CalorieParserTest {
+
+ //@@author calebcjl
+ @Test
+ void parseAddCalorieCommand_negativeCalorieCount_expectInvalidArgumentException() {
+ String argument = "11/12/22 Food -10";
+ assertThrows(InvalidArgumentException.class, () -> parseAddCalorieCommand(argument));
+ }
+
+ @Test
+ void parseAddCalorieCommand_noFoodName_expectInvalidArgumentException() {
+ String argument1 = "11/12/22 100";
+ assertThrows(InvalidArgumentException.class, () -> parseAddCalorieCommand(argument1));
+ String argument2 = "11/12/22 100";
+ assertThrows(InvalidArgumentException.class, () -> parseAddCalorieCommand(argument2));
+ }
+
+ @Test
+ void parseListCalorieCommand_notBlankArgument_expectInvalidSyntaxException() {
+ String argument1 = "@";
+ assertThrows(InvalidSyntaxException.class, () -> parseListCalorieCommand(argument1));
+ String argument2 = "2";
+ assertThrows(InvalidSyntaxException.class, () -> parseListCalorieCommand(argument2));
+ }
+
+ @Test
+ void parseDeleteCalorieCommand_multipleIntegers_expectInvalidSyntaxException() {
+ String argument = "11/12/22 1 2";
+ assertThrows(InvalidSyntaxException.class, () -> parseDeleteCalorieCommand(argument));
+ }
+}
diff --git a/src/test/java/seedu/parser/ParserTest.java b/src/test/java/seedu/parser/ParserTest.java
new file mode 100644
index 0000000000..f148247243
--- /dev/null
+++ b/src/test/java/seedu/parser/ParserTest.java
@@ -0,0 +1,37 @@
+package seedu.parser;
+
+
+import org.junit.jupiter.api.Test;
+import seedu.commands.Command;
+import seedu.commands.ExitCommand;
+import seedu.commands.errorcommands.IncorrectSyntaxCommand;
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+import static org.testng.AssertJUnit.assertFalse;
+
+
+//@@author ZIZI-czh
+public class ParserTest {
+
+ /**
+ * Test the input for list command
+ * if the user type in user /list 556 which is incorrect, then it will show error
+ */
+ //@@ author ZIZI-czh
+ @Test
+ public void testProcessCommandIncorrectArguments() {
+ String userInput = "/wlist 556";
+ Parser testList = new Parser();
+ Command result;
+ try {
+ result = testList.parseCommand(userInput);
+ } catch (InvalidSyntaxException e) {
+ result = new ExitCommand();
+ } catch (InvalidArgumentException e) {
+ throw new RuntimeException(e);
+ }
+ //show error, if the result satisfy the condition in IncorrectCommand
+ assertFalse(result instanceof IncorrectSyntaxCommand);
+ }
+
+}
diff --git a/src/test/java/seedu/parser/WorkoutParserTest.java b/src/test/java/seedu/parser/WorkoutParserTest.java
new file mode 100644
index 0000000000..81b5a1b700
--- /dev/null
+++ b/src/test/java/seedu/parser/WorkoutParserTest.java
@@ -0,0 +1,44 @@
+package seedu.parser;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.exceptions.InvalidArgumentException;
+import seedu.exceptions.InvalidSyntaxException;
+
+import static org.junit.Assert.assertThrows;
+import static seedu.parser.WorkoutParser.parseAddExerciseCommand;
+import static seedu.parser.WorkoutParser.parseEndWorkoutCommand;
+
+
+class WorkoutParserTest {
+ //@@author calebcjl
+ @Test
+ void parseAddExerciseCommand_emptyExerciseName_expectInvalidArgumentException() {
+ String addExerciseArgument1 = " 100kg 5 5 5 5";
+ assertThrows(InvalidArgumentException.class, () -> parseAddExerciseCommand(addExerciseArgument1));
+ String addExerciseArgument2 = "100kg 5 5 5 5";
+ assertThrows(InvalidArgumentException.class, () -> parseAddExerciseCommand(addExerciseArgument2));
+ }
+
+ @Test
+ void parseAddExerciseCommand_invalidWeight_expectException() {
+ String addExerciseArgument1 = "ExerciseName 100 kg 5 5 5 5";
+ assertThrows(InvalidArgumentException.class, () -> parseAddExerciseCommand(addExerciseArgument1));
+ String addExerciseArgument2 = "ExerciseName 100kh 5 5 5 5";
+ assertThrows(InvalidSyntaxException.class, () -> parseAddExerciseCommand(addExerciseArgument2));
+ }
+
+ @Test
+ void parseAddExerciseCommand_multiWhiteSpacesInRps_expectInvalidArgumentException() {
+ String addExerciseArgument1 = "ExerciseName 100kg 5 5 5 5";
+ assertThrows(InvalidArgumentException.class, () -> parseAddExerciseCommand(addExerciseArgument1));
+ }
+
+ @Test
+ void parseEndWorkoutCommand_argumentNotEmpty_expectInvalidSyntaxException() {
+ String endWorkoutArguments1 = "argument";
+ assertThrows(InvalidSyntaxException.class, () -> parseEndWorkoutCommand(endWorkoutArguments1));
+ String endWorkoutArguments2 = "1";
+ assertThrows(InvalidSyntaxException.class, () -> parseEndWorkoutCommand(endWorkoutArguments2));
+ }
+}
diff --git a/src/test/java/seedu/workout/ExerciseTest.java b/src/test/java/seedu/workout/ExerciseTest.java
new file mode 100644
index 0000000000..cfda5d6cf1
--- /dev/null
+++ b/src/test/java/seedu/workout/ExerciseTest.java
@@ -0,0 +1,28 @@
+package seedu.workout;
+
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+//@@author guillaume-grn
+public class ExerciseTest {
+
+ @Test
+ public void testGetSetsCount() {
+ Exercise exercise = new Exercise("deadlift", "100", "8 8 9");
+ int expected = 3;
+ int actual = exercise.getSetsCount();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetRepsCount() {
+ Exercise exercise1 = new Exercise("Bench Press", "100kg", "8 6 4");
+ Exercise exercise2 = new Exercise("Squats", "80kg", "10 10 10 10");
+
+ assertEquals(18, exercise1.getRepsCount());
+ assertEquals(40, exercise2.getRepsCount());
+ }
+}
+
diff --git a/src/test/java/seedu/workout/WorkoutListTest.java b/src/test/java/seedu/workout/WorkoutListTest.java
new file mode 100644
index 0000000000..43953f816c
--- /dev/null
+++ b/src/test/java/seedu/workout/WorkoutListTest.java
@@ -0,0 +1,122 @@
+package seedu.workout;
+
+
+import org.junit.jupiter.api.Test;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+
+//@@author ZIZI-czh
+class WorkoutListTest {
+ @Test
+ public void testStartWorkout() throws Exception {
+ // Initialize a new WorkoutList
+ WorkoutList workoutList = new WorkoutList();
+
+ // Check that the list is empty
+ assertTrue(workoutList.isEmptyList());
+
+ // Add a new workout
+ Date date = new Date();
+ workoutList.startWorkout(date, "Workout 1");
+
+ // Check that the list is not empty
+ assertFalse(workoutList.isEmptyList());
+
+ // Check that the current workout index is set to the correct value
+ assertEquals(0, workoutList.getCurrentWorkoutIndex());
+
+ // Check that the workout was added to the list
+ ArrayList workouts = workoutList.getWorkouts();
+ assertEquals(1, workouts.size());
+ assertEquals(date, workouts.get(0).getDate());
+ assertEquals("Workout 1", workouts.get(0).getWorkoutName());
+ }
+
+ @Test
+ public void testGetWorkoutsInSpecificWeek() throws Exception {
+ // Initialize a new WorkoutList
+ WorkoutList workoutList = new WorkoutList();
+
+ // Add some workouts to the list
+ Date date1 = new Date();
+ workoutList.startWorkout(date1, "Workout 1");
+ Date date2 = new Date(date1.getTime() + 604800000); // Add one week to date1
+ workoutList.startWorkout(date2, "Workout 2");
+ Date date3 = new Date(date2.getTime() + 604800000); // Add one week to date2
+ workoutList.startWorkout(date3, "Workout 3");
+
+ // Get the workouts for the second week
+ ArrayList workouts = workoutList.getWorkoutsInSpecificWeek(date2);
+
+ // Check that the correct number of workouts were returned
+ assertEquals(1, workouts.size());
+
+ // Check that the correct workout was returned
+ assertEquals(date2, workouts.get(0).getDate());
+ assertEquals("Workout 2", workouts.get(0).getWorkoutName());
+ }
+
+ @Test
+ public void testCountSetsReps() throws Exception {
+ ArrayList workouts = new ArrayList<>();
+ Date date1 = DateFormatter.stringToDate("4/4/23");
+ Date date2 = DateFormatter.stringToDate("6/4/23");
+ Date date3 = DateFormatter.stringToDate("8/4/23");
+
+ // create workout 1
+ Workout workout1 = new Workout(date1, "Workout 1");
+ Exercise exercise1 = new Exercise("BenchPress", "45kg", "5 5 5 5");
+ Exercise exercise2 = new Exercise("Squats", "50kg", "6 6 6 6");
+ workout1.addExercise(exercise1);
+ workout1.addExercise(exercise2);
+ workouts.add(workout1);
+
+ // create workout 2
+ Workout workout2 = new Workout(date2, "Workout 2");
+ Exercise exercise3 = new Exercise("Bench Press", "45kg", "2 2 2 2");
+ Exercise exercise4 = new Exercise("Dead lifts", "45kg", "5 5 5 5");
+ workout2.addExercise(exercise3);
+ workout2.addExercise(exercise4);
+ workouts.add(workout2);
+
+ // create workout 3
+ Workout workout3 = new Workout(date3, "Workout 3");
+ Exercise exercise5 = new Exercise("Squats", "45kg", "5 5 6 5 5");
+ Exercise exercise6 = new Exercise("Dead lifts", "65kg", "5 5 5 6 5");
+ workout3.addExercise(exercise5);
+ workout3.addExercise(exercise6);
+ workouts.add(workout3);
+
+ // create workout list
+ WorkoutList workoutList = new WorkoutList(workouts);
+
+ // count sets and reps for week of April 3, 2023
+ Date weekStart = DateFormatter.stringToDate("3/4/23");
+ String result = workoutList.countSetsReps(weekStart);
+
+ // expected output
+ String expected = "Information of exercises for the week of 03/04/23" +
+ System.lineSeparator() +
+ "Name: Squats, sets: 9, rps: 50" +
+ System.lineSeparator() +
+ "Name: Bench Press, sets: 4, rps: 8" +
+ System.lineSeparator() +
+ "Name: Dead lifts, sets: 9, rps: 46" +
+ System.lineSeparator() +
+ "Name: BenchPress, sets: 4, rps: 20" +
+ System.lineSeparator() +
+ Ui.line();
+
+ // check if expected output matches actual output
+ assertEquals(expected, result);
+ }
+}
diff --git a/src/test/java/seedu/workout/WorkoutTest.java b/src/test/java/seedu/workout/WorkoutTest.java
new file mode 100644
index 0000000000..ccc6d20926
--- /dev/null
+++ b/src/test/java/seedu/workout/WorkoutTest.java
@@ -0,0 +1,83 @@
+package seedu.workout;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.parser.DateFormatter;
+import seedu.ui.Ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+//@@ author ZIZI-czh
+public class WorkoutTest {
+ private static final Date date = new Date();
+ private static final String WORKOUT_NAME = "Test Workout";
+ private Workout workout;
+ private Exercise exercise1;
+ private Exercise exercise2;
+
+
+
+ //@@ author ZIZI-czh
+ @BeforeEach
+ public void setUp() {
+ workout = new Workout();
+ exercise1 = new Exercise("Bench Press", "100kg", "8 6 4 8");
+ exercise2 = new Exercise("Squats", "80kg", "10 10 10 10");
+ }
+
+ @Test
+ public void testGetWorkoutName() {
+ Workout workout = new Workout(date, WORKOUT_NAME);
+ assertEquals(WORKOUT_NAME, workout.getWorkoutName());
+ }
+
+
+ @Test
+ public void testGetDate() {
+ Workout workout = new Workout(date, WORKOUT_NAME);
+ assertEquals(date, workout.getDate());
+ }
+
+ @Test
+ public void testGetExercises() {
+ Workout workout = new Workout(date, WORKOUT_NAME);
+ ArrayList exercises = workout.getExercises();
+ assertTrue(exercises.isEmpty());
+ }
+ //@@ author ZIZI-czh
+ @Test
+ public void testAddExercise() {
+ workout.addExercise(exercise1);
+ ArrayList exercises = workout.getExercises();
+ Assertions.assertEquals(1, exercises.size());
+ Assertions.assertEquals(exercise1, exercises.get(0));
+
+ workout.addExercise(exercise2);
+ exercises = workout.getExercises();
+ Assertions.assertEquals(2, exercises.size());
+ Assertions.assertEquals(exercise2, exercises.get(1));
+ }
+
+ @Test
+ public void testToString() {
+ Workout workout = new Workout(date, WORKOUT_NAME);
+ Exercise exercise1 = new Exercise("Test Exercise 1", "36kg", "4 4 4");
+ Exercise exercise2 = new Exercise("Test Exercise 2", "50kg", "4 4 6 5");
+ workout.addExercise(exercise1);
+ workout.addExercise(exercise2);
+
+ String expected = "Here are the list of exercises for Test Workout on "
+ + DateFormatter.dateToString(date) + '.' + System.lineSeparator()
+ + "1. Test Exercise 1 36kg 4 4 4" + System.lineSeparator()
+ + "2. Test Exercise 2 50kg 4 4 6 5" + System.lineSeparator()
+ + Ui.line();
+ assertEquals(expected, workout.toString());
+ }
+
+}
+
diff --git a/text-ui-test/ACTUAL.TXT b/text-ui-test/ACTUAL.TXT
new file mode 100644
index 0000000000..2f4d760251
--- /dev/null
+++ b/text-ui-test/ACTUAL.TXT
@@ -0,0 +1,26 @@
+Let's get moving!
+"/start " to begin your workout
+Started new workout.
+Use add command to add exercises to your workout!
+Added Bench Press 100kg 6 5 4 4 3
+Added Cable Flys 30kg 10 10 10
+Invalid date format. Please enter the date in the format dd/mm/yy.
+Incorrect command given!
+Great job completing your workout!
+Started new workout.
+Use add command to add exercises to your workout!
+Here are the list of dates for your workout:
+11-11-23
+11-10-23
+Added tricep extensions 25kg 8 7 6
+Great job completing your workout!
+Started new workout.
+Use add command to add exercises to your workout!
+Added Pullups +10kg 10 10 10
+Great job completing your workout!
+Workout deleted successfully.
+No workout found with the specified date.
+Here are the list of dates for your workout:
+11-10-23
+12-11-23
+Thank you and see you next time
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..dc5eba09f7 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +1,24 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
+Let's get moving!
+"/start " to begin your workout
+Started new workout.
+Use add command to add exercises to your workout!
+Added Bench Press 100kg 6 5 4 4 3
+Added Cable Flys 30kg 10 10 10
+Invalid date format. Please enter the date in the format dd/mm/yy.
+Incorrect command given!
+Great job completing your workout!
+Here are the list of dates for your workout:
+11-11-23
+11-10-23
+Start a workout first!
+Great job completing your workout!
+Started new workout.
+Use add command to add exercises to your workout!
+Added Pullups +10kg 10 10 10
+Great job completing your workout!
+Workout deleted successfully.
+No workout found with the specified date.
+Here are the list of dates for your workout:
+11-10-23
+12-11-23
+Thank you and see you next time
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..65fe834a18 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +1,16 @@
-James Gosling
\ No newline at end of file
+/start 11/11/23
+/add Bench Press /weight 100kg /rps 6 5 4 4 3
+/add Cable Flys /weight 30kg /rps 10 10 10
+/start
+/end
+/start 11/10/23
+/list
+/add tricep extensions /weight 25kg /rps 8 7 6
+/end
+/start 12/11/23
+/add Pullups /weight +10kg /rps 10 10 10
+/end
+/delete 11/11/23
+/delete 11/12/23
+/list
+/exit
\ No newline at end of file