diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..e26fd17aea
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: seedu.duke.Duke
+
diff --git a/README.md b/README.md
index f82e2494b7..396b4744d0 100644
--- a/README.md
+++ b/README.md
@@ -62,3 +62,4 @@ Steps for publishing documentation to the public:
1. Scroll down to the `GitHub Pages` section.
1. Set the `source` as `master branch /docs folder`.
1. Optionally, use the `choose a theme` button to choose a theme for your documentation.
+
diff --git a/build.gradle b/build.gradle
index ea82051fab..5cb0cdfb3a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -41,6 +41,7 @@ checkstyle {
toolVersion = '10.2'
}
-run{
+run {
standardInput = System.in
+ enableAssertions = true
}
diff --git a/data/events/event.txt b/data/events/event.txt
new file mode 100644
index 0000000000..4d5463886c
--- /dev/null
+++ b/data/events/event.txt
@@ -0,0 +1 @@
+Do User | 2023-12-20T12:30:30 | 2023-12-20T13:30:30
diff --git a/data/flashcards/flashcard 1124.txt b/data/flashcards/flashcard 1124.txt
new file mode 100644
index 0000000000..9662c3e1dc
--- /dev/null
+++ b/data/flashcards/flashcard 1124.txt
@@ -0,0 +1 @@
+3 | Hello | Duke | - | - | -
diff --git a/data/flashcards/flashcard 18.50.11.txt b/data/flashcards/flashcard 18.50.11.txt
new file mode 100644
index 0000000000..1000ff8298
--- /dev/null
+++ b/data/flashcards/flashcard 18.50.11.txt
@@ -0,0 +1,2 @@
+2 | d | a | - | 2023-11-02T00:03:45.242754100 # MODERATE/2023-11-02T00:03:47.250188600 # EASY/2023-11-02T00:03:49.267332500 # HARD/2023-11-02T00:16:31.511531100 # MODERATE/2023-11-02T00:18:58.600168500 # MODERATE/2023-11-02T00:19:05.649443900 # MODERATE | -
+4 | Hello | Duke | - | - | -
diff --git a/data/flashcards/flashcard.txt b/data/flashcards/flashcard.txt
new file mode 100644
index 0000000000..b989a3e76c
--- /dev/null
+++ b/data/flashcards/flashcard.txt
@@ -0,0 +1,19 @@
+2 | Hello | Duke | 5
+3 | Hello | Duke | 5
+4 | Hello | Duke | 5
+5 | Hello | Duke | 5
+6 | Hello | Duke | 5
+7 | Hello | Duke | 5
+8 | Hello | Duke | 5
+9 | Hello | Duke | 5
+10 | Hello | Duke | 5
+11 | Hello | Duke | 5
+12 | Hello | Duke | 5
+13 | Hello | Duke | 5
+14 | Hello | Duke | 5
+15 | Hello | Duke | 5
+16 | Hello | Duke | 5
+17 | Hello | Duke | 5
+18 | Hello | Duke | 5
+19 | Hello | Duke | 5
+20 | Hello | Duke | 5
diff --git a/data/flashcards/flashcard1110.txt b/data/flashcards/flashcard1110.txt
new file mode 100644
index 0000000000..acf345ab1d
--- /dev/null
+++ b/data/flashcards/flashcard1110.txt
@@ -0,0 +1,3 @@
+3 | cs2113 | software enginnering | 3
+5 | Hello | Duke | 4
+7 | Hello | Duke | 5
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..794af66edd 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,9 @@
# 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://media.licdn.com/dms/image/C4D03AQGTLbALYjG82Q/profile-displayphoto-shrink_800_800/0/1580629728751?e=1701907200&v=beta&t=PEfw_qZfZA39rJRfo5_Pg4o_RmbPwdneiPX3ftNt9dA) | Wendelin Wemhoener | [Github](https://github.com/wendelinwemhoener/) | [Portfolio](https://ay2324s1-cs2113-f11-3.github.io/tp/team/wendelinwemhoener.html)
+![](https://via.placeholder.com/100.png?text=Photo) | Zhu Jingxi | [Github](https://github.com/Cheezeblokz) | [Portfolio](docs/team/zhujingxi.md)
+![](/Users/brian/Desktop/Colgate/NUS Fall 2023/CS2113/Team Project/docs/photo/kherlenbayasgalan.jpg) | Kherlen Bayasgalan | [Github](https://github.com/Brian030601) | [Portfolio](docs/team/brian030601.md)
+![](https://via.placeholder.com/100.png?text=Photo) | Bang Junhyeong | [Github](https://github.com/junhyeong0411) | [Portfolio](docs/team/bangjunhyeong.md)
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 64e1f0ed2b..90045e8c7a 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,38 +1,447 @@
-# Developer Guide
+# **Developer Guide**
-## Acknowledgements
+## **Acknowledgements**
-{list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
++ Acknowledgement to the [CS2113 Website](https://nus-cs2113-ay2324s1.github.io/website/admin/tp-deliverables.html#deliverable-project-portfolio-page-ppp) for giving us design guidelines.
++ Acknowledgement to [Dr Akshay Narayan](https://www.comp.nus.edu.sg/cs/people/anarayan/), and Teaching Assistant for their guidance.
++ Acknowledgement to [team members](AboutUs.md) for their hard work.
++ Acknowledgement to the [diagram tool](https://app.diagrams.net) for facilitating drawing of diagrams
++ Acknowledgement to [Developer Guide Example](https://se-education.org/addressbook-level3/DeveloperGuide.html#acknowledgements) for illustration.
-## Design & implementation
+## **Design & implementation**
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+### **Design & Architecture**
+Given below is a quick overview of main components and how they interact with each other.
-## Product scope
-### Target user profile
+![High-level Design of TaskLinker](photo/OverallDesign.png)
-{Describe the target user profile}
+**Main components of the architecture**
-### Value proposition
+The two main classes of Duke are FlashcardComponent and CalendarManager.
+Those two classes carry out the bulk of the application.
-{Describe the value proposition: what problem does it solve?}
+Duke prompts for user input. Duke also has accesses to FlashcardComponent
+and CalendarManager. So, when the user input is given, duke decided which one
+to call based on the input.
-## User Stories
+As the input is processed and called by one of the two main classes,
+subsequent methods and features are called by children classes. The
+low-class explanations will be given below.
-|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|
+### **`flashcard` package**
-## Non-Functional Requirements
+#### **Package structure overview**
-{Give non-functional requirements}
+The API of the `flashcard` package is defined in [`FlashcardComponent.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardComponent.java).
-## Glossary
+The flashcard package is structured into multiple parts:
-* *glossary item* - Definition
+- [`Flashcard.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/Flashcard.java):
+ Represents a single flashcard with front text, back text as well as
+ its unique id and current difficulty level.
+- [`FlashcardCommandParser.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java):
+ Parses user inputs into the corresponding commands.
+- [`FlashcardComponent.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardComponent.java):
+ Encapsulates all functionality of the `flashcard` package and exposes it
+ in one single, unified API.
+- [`FlashcardDirectory.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardDirectory.java):
+ Helper class needed for storing flashcards after TaskLinker has been
+ exited; see [the DG section about storage components](#storage-components).
+- [`FlashcardList.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardList.java):
+ Container class for a list of flashcards. Exposes a simple, unified API
+ for dealing with a list of flashcards.
+- [`FlashcardUi.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/FlashcardUi.java):
+ Responsible for interfacing with the user: dispatches commands to be
+ executed and shows their output to the user.
+- [`flashcard.command` package](https://github.com/AY2324S1-CS2113-F11-3/tp/tree/master/src/main/java/seedu/duke/flashcard/command):
+ Contains classes representing the different kinds of commands (`list
+ flashcards`, `create flashcard` etc.).
+- [`flashcard.exceptions` package](https://github.com/AY2324S1-CS2113-F11-3/tp/tree/master/src/main/java/seedu/duke/flashcard/exceptions):
+ Contains classes representing custom exceptions that are specific to the
+ `flashcards` package.
+- [`flashcard.review` package](https://github.com/AY2324S1-CS2113-F11-3/tp/tree/master/src/main/java/seedu/duke/flashcard/review):
+ Contains classes representing the different flashcard review modes (random
+ mode and spaced repetition mode).
-## Instructions for manual testing
+This class diagram provides a high-level overview of how the classes in the
+top-level `flashcard` package integrate with each other:
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+![class diagram of classes providing flashcard functionality](Diagrams/flashcard-diagrams/overview_classes.svg)
+
+#### **Rough control flow overview**
+
+The process of processing the initial user input and figuring out which
+command to execute based on this user input is handled by the
+`FlashcardComponent`, `FlashcardCommandParser` and `FlashcardUi` classes.
+
+During their operation, they create an instance of the appropriate
+`FlashcardCommand` (from the `flashcard.command` package) and then execute
+it; thereby performing the action the user wanted.
+
+Put into a sequence diagram flow, the above-mentioned workflow looks like this:
+
+![sequence diagram of processing the list flashcards input](Diagrams/flashcard-diagrams/overview_sequence.svg)
+
+This workflow is divided into multiple parts:
+
+1. When the user enters text ("list flashcards" in this specific case), `Duke`
+ first tries to figure out whether the flashcard package is responsible for
+ handling it. To this end, `Duke` calls the `isResponsible` method of
+ `FlashcardComponent`.
+2. The `isResponsible` method works by passing the input on to
+ `FlashcardCommandParser` and checking whether it returns an
+ UnknownCommand or not. In this specific case, `FlashcardCommandParser`
+ recognizes the "list flashcards" input and returns a matching
+ `ListFlashcardsCommand`. Thus, the `FlashcardComponent` knows that it
+ can process the inputted text and thus is responsible for handling it.
+ Thus, true is returned.
+3. Because `FlashcardComponent` has returned `true` as response to the call
+ of its `isResponsbile` method, `Duke` passes the user input on to
+ `FlashcardComponent` via the `processInput` method.
+4. Just like when executing the `isResponsible` method, `FlashcardComponent`
+ passes the input on to `FlashcardCommandParser` and in this specific case
+ gets back a `ListFlashcardsCommand`.
+5. `FlashcardComponent` now passes this `ListFlashcardsCommand` on to the
+ `FlashcardUi` by invoking the latter's `executeCommand` method.
+6. The `FlashcardUi` in turn calls the `execute` method of the
+ `ListFlashcardsCommand` it has just been passed.
+7. The `ListFlashcardsCommand` is executed, showing a list of all flashcards
+ to the user, before control is returned to `Duke`.
+
+#### **`flashcard.command` package**
+
+The `flashcard.command` package contains the classes representing the
+different flashcard commands.
+
+These are the classes representing the different commands:
+- [`CreateFlashcardCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/CreateFlashcardCommand.java)
+ corresponds to the `create flashcards` command
+- [`DeleteAllFlashcardsCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java)
+ corresponds to the `delete all flashcards` command
+- [`DeleteFlashcardCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java)
+ corresponds to the `delete flashcard` command
+- [`ListFlashcardsCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java)
+ corresponds to the `list flashcards` command
+- [`StartReviewCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java)
+ corresponds to the `review flashcards` command
+
+All these classes inherit from the abstract class `FlashcardCommand` and
+define its `execute` method. This method serves as the entire API of a
+`FlashcardCommand`: The `execute` method is passed a scanner and an instance
+of `FlashcardList` that represents the currently used flashcards and then
+performs any actions necessary to execute the respective command.
+
+Subclasses of `FlashcardCommand` are free to implement any additional
+private or protected fields and/or methods that are required for their
+internal operation. In this regard, because the commands all achieve very
+different goals (listing flashcards vs creating new flashcards), the different
+subclasses of `FlashcardCommand` can vary quite heavily. Therefore, in the
+interest of brevity, the individual subclasses are not explained in further
+detail and the reader is instead referred to their respective source code in
+the `src/main/java/seedu.duke/flashcard/command` directory.
+
+##### "Dual Commands": Offering different input options for beginner vs expert users
+
+As already explained in the user guide, there are so-called "Dual Commands"
+that can be invoked in two different ways: an easy, but more time-consuming way
+for beginner users who want as much guidance as possible; or a less
+time-consuming, but more complicated way for expert users who don't need
+additional guidance. Such "dual commands" are implemented as subclasses of
+the abstract class `DualFlashcardCommand`.
+
+Currently, the following commands are dual commands (and as such inherit
+from `DualFlashcardCommand`):
+
+- [`DeleteFlashcardCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java)
+- [`StartReviewCommand.java`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java)
+
+The abstract `DualFlashcardCommand` mode contains two abstract methods that
+need to be implemented by its subclasses:
+
+- `executeBeginnerMode`: Implementing this abstract method allows implementing
+ the beginner mode (with interactive input) that allows for easier, but
+ more time-consuming usage.
+- `executeExpertMode`: Implementing this abstract method allows implementing
+ the expert mode (with one-line input) that allows for less time-consuming,
+ but more complicated usage.
+
+This class diagram depicts the internal structure of the `flashcard.command`
+package and especially highlights how `CreateFlashcardCommand`,
+`DeleteAllFlashcardsCommand` and `ListFlashcardsCommand` directly inherit
+from `FlashcardCommand`; whereas `DeleteFlashcardCommand` and
+`StartReviewCommand` inherit from `DualFlashcardCommand` which in itself
+inherits from `FlashcardCommand`:
+
+![class diagram of flashcard.command package](Diagrams/flashcard-diagrams/command_package_classes.svg)
+
+#### **`flashcard.exceptions` package**
+
+This package contains the `FlashcardException` base class from which all
+flashcard-specific exceptions are derived.
+
+Individual, flashcard-specific exceptions are implemented as subclasses of
+the `FlashcardException` class. For further details, you can see the Javadoc
+comments in their source code.
+
+Currently, the flashcard-specific exceptions are:
+
+- [`InvalidFlashcardIdException`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/exceptions/InvalidFlashcardIdException.java):
+ Signifies that a given flashcardId is not valid, i.e. that no flashcard with
+ that id appears in the list of flashcards which are currently being worked on.
+- [`InvalidReviewModeException`](https://github.com/AY2324S1-CS2113-F11-3/tp/blob/master/src/main/java/seedu/duke/flashcard/exceptions/InvalidReviewModeException.java):
+ Signifies that an invalid, i.e. non-existent review mode has been chosen.
+
+#### **`flashcard.review` package**
+
+This package contains all classes related to review modes for flashcards.
+
+It contains the `ReviewMode` base class that provides functionalities to
+easily review flashcards that can be used by subclasses as building blocks to
+implement specific kinds of reviews (e.g. random or spaced repetition reviews).
+
+There are two subclasses which inherit from `ReviewMode`, namely
+`RandomReviewMode` and `SpacedRepetitionReviewMode`.
+
+In this regard, because the different review modes all use very
+different revision strategies (random picking vs difficulty-based picking of
+flashcards), the different subclasses of `ReviewMode` can vary quite heavily.
+Therefore, in the interest of brevity, the individual subclasses are not
+explained in further detail and the reader is instead referred to their
+respective source code in the `src/main/java/seedu.duke/flashcard/review`
+directory.
+
+### **Storage Components**
+
+API: `FlashcardStorage.java`
+
+![Flashcard Storage Sequence Diagram](photo/FlashcardStorage-0.png)
+
+The `FlashcardStorage` component,
+* can creates data directory and flashcards directory.
+* can save flashcards in `flashcard.txt` in specific text format
+* saves automatically when changes occur.
+* component loads automatically when the program starts.
+* component can check if the saved txt file has been damaged.
+
+`EventStorage` has similar structure. (It was omitted to avoid redundancy.)
+
+### **Calendar Components**
+
+API: `CalendarManager.java`
+
+#### **Command Package**
+
+The package has 7 files in it for users to command their calendar. Those files are
+AddEventCommand, DeleteAllEventsCommand, DeleteEventCommand, EventCommand, FindEventCommand
+ListEventCommand, and UnknownCommand. The other 6 commands extend EventCommand, which is
+an abstract class that forces other 6 commands to have an execute method.
+
+
+Each command files execute its own commands. The UnknownCommand file handles the exceptions,
+such as if the user commands something that doesn't exist
+
+#### **Calendar Package**
+
+The calendar package excluding the command package has 8 classes.
+The Calendar class integrates flashcards and calendar events, allowing for interactions between the 2 packages.
+The CalendarManager, EventStorage, & CalendarCommandParser manages user input, saves, and loads them.
+The classes are associated with one another through instant accesses and other means. The
+CalendarManager directs the events and event list, which then are run on Duke.
+
+Calendar package Class Diagram:
+![Calendar package Class Diagram](photo/CalendarManagerClassDiagram.drawio.png)
+
+CalendarManager Sequence Diagram:
+![CalendarManager Sequence Diagram](photo/CalendarManagerSequenceDiagram.drawio.png)
+
+## **Product scope**
+
+### **Target user profile**
+
+TaskLinker is tailored towards university students who use flashcards to
+study for their courses and need an easy way to schedule and plan the
+studying of their flashcards as well as track some other tasks in their
+calendar.
+
+TaskLinker is a CLI tool and as such, it is tailored towards students who
+type fast and prefer a functional, but bare-bones app that runs in the
+terminal over a GUI that looks more impressive but is slower to use.
+
+As such, computer science students represent good target users of TaskLinker.
+
+### **Value proposition**
+
+TaskLinker is a CLI-tool for helping university students memorize flashcards
+and track their flashcard progress as well as general academic progress in
+the courses they are taking.
+
+## **User Stories**
+
+| Version | As a ... | I want to ... | So that I can ... |
+|---------|---------------------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
+| v1.0 | user | Delete event from my Calendar | remove unnecessary events from the Calendar |
+| v1.0 | user | Add event to my Calendar | create new necessary events on my Calendar |
+| v1.0 | user | List all events in my Calendar | keep track of all my events and deadlines |
+| v1.0 | user | list all my flashcards | get a quick overview of my flashcard collection |
+| v1.0 | user | create new flashcards | add new knowledge I want to study |
+| v1.0 | user | review my flashcards | so that I can memorize their contents |
+| v2.0 | new user | be able to invoke a help command | get advice/tips for how to use TaskLinker if I don' know how |
+| v2.0 | user reviewing flashcards | rate how hard it was to remember their content | see harder flashcards more often and easy flashcards less frequently during reviews |
+| v2.0 | experienced user | use the delete and review feature by typing a one-line command | be faster than having to go through the prompt-answer workflow these features usually require |
+| v2.0 | user | find events from my Calendar | find events without listing them all |
+| v2.0 | user | delete all events from my Calendar | don't need to remove events one by one |
+| v2.0 | user | add a goal event to my Calendar | remember how many flashcards needs to be reviewed by a certain deadline |
+
+## **Non-Functional Requirements**
+
++ Software Requirements:
+ 1. The TaskLinker should be able to run on one of Windows, macOS, or Linux operating systems.
+ 2. The TaskLinker must be able to run on Java 11 or above Java versions.
+
++ Technical Requirements:
+ 1. Users should not manually interact with storage files.
+ 2. If the input is not in acceptable format, the program shouldn't execute anything
+ 3. If the correct command is not given, the program should not execute any command.
+ 4. The application should only work with English language.
+
++ General Requirements:
+ 1. The application should not crash on any given exceptions due to exceptions handling.
+ 2. The dates/time should always be in yyyy-MM-ddTHH:mm:ss format.
+ 3. The application must be able to support as many events as needed.
+ 4. The application must be able to support as many flashcards as needed.
+ 5. The application can be used by anyone who can read and type.
+
+
+## **Glossary**
+
+* *TaskLinker* - CLI-tool for helping university students memorize flashcards
+ and track their flashcard and general academic progress in the courses they are
+ taking.
+* *Calendar* - A place where all the events are listed with start and end time.
+* *Event* - A task to be done from a given time to end time.
+* *Flashcard* - A study tool to memorize a given word.
+* *Storage* - A file where the calendar and flashcards are stored.
+* *Goal* - A goal to be accomplished by a given date/time on the calendar.
+* *Review* - Study flashcards
+* *Exception* - Something abnormal that should not happen.
+* *UML Diagram* - A diagram where the design of the application is explained.
+* *DeveloperGuide* - A guide for other developers to read to understand the application.
+* *UserGuide* - A guide for the users to read to understand the application.
+
+## **Instructions for manual testing**
+
+*Given below are the instructions for manual testing the TaskLinker.*
+
+### **Testing launching and exiting the application**
+Launching the application
+ 1. download the jar file from the release page.
+ 2. open a terminal and navigate to the directory where the jar file is located.
+ 3. run the command `java -jar TaskLinker.jar`
+
+Exiting the application
+ 1. type `exit` in the command box and press enter.
+ 2. the application will exit.
+
+#### **Testing adding an event to the calendar**
+
+Test Case #1 (Everything Works):
+
+
+Enter your command: add event
+What's the event?: Do HW
+When does it start?: 2023-12-20T12:30:30
+When does it end?: 2023-12-20T13:40:30
+
+
+Test Case #2 (Start Time, End Time Error):
+
+
+Enter your command: add event
+What's the event?: Do HW
+When does it start?: 2023-12-20T12:30:30
+When does it end?: 2023-12-20T11:40:30
+
+ End time is before or equal to the start time. Please enter the correct end time.
+
+
+#### **Testing adding a goal event to the calendar**
+
+Test Case #1 (Everything Works):
+
+
+Enter your command: add goal event
+What's the event?: Do Flashcards
+When does it end?: 2023-12-20T12:30:30
+
+Goal 'Do Flashcards' review 20 flashcards by: 2023-12-20T12:30:30 (Reviewed: 0)
+has been added to your Calendar
+
+
+Test Case #2 (Not an integer for # of flashcards):
+
+
+Enter your command: add goal event
+What's the event?: Do Flashcards
+When does it end?: 2023-12-20T12:30:30
+How many flashcard to review by then?: r
+
+ Invalid integer input. Please try again.
+
+
+#### **Testing deleting an event from the calendar**
+
+Test Case #1 (Everything Works):
+
+
+Enter your command: delete event
+What's the event?: hello
+ hello has been deleted from your Calendar!
+
+
+Test Case #2 (Incomplete command):
+
+
+Enter your command: delete
+☹ OOPS!!! The description of a delete cannot be empty.
+ Invalid integer input. Please try again.
+
+
+#### **Testing finding an event from the Calendar**
+
+Test Case #1 (Everything Works):
+
+
+Enter your command: find event
+What's the event?: Do HW
+1. Event 'Do HW' From: 2023-12-20T12:30:30, To: 2023-12-20T13:30:30
+ These events have been found
+
+
+Test Case #2 (Incomplete Command):
+
+
+Enter your command: find
+☹ OOPS!!! The description of a find cannot be empty.
+ Invalid integer input. Please try again.
+
+
+#### **Testing listing all events from the Calendar**
+
+Test Case #1 (Everything Works):
+
+
+Enter your command: list events
+ Here is a list of all your events:
+--------------------------------------------------------------------------------
+1. Event 'Do User' From: 2023-12-20T12:30:30, To: 2023-12-20T13:30:30
+--------------------------------------------------------------------------------
+
+
+Test Case #2 (Incomplete command):
+
+
+Enter your command: list
+☹ OOPS!!! The description of a list cannot be empty.
+ Invalid integer input. Please try again.
+
\ No newline at end of file
diff --git a/docs/Diagrams/FlashcardStorage.puml b/docs/Diagrams/FlashcardStorage.puml
new file mode 100644
index 0000000000..32622417fb
--- /dev/null
+++ b/docs/Diagrams/FlashcardStorage.puml
@@ -0,0 +1,61 @@
+@startuml
+
+participant ":FlashcardComponent" as fc
+participant ":FlashcardDirectory" as fd
+participant ":FlashcardStorage" as fs
+participant ":FlashcardList" as fl2
+participant ":FlashcardList" as fl
+participant ":FlashcardStorageParser" as fp
+
+
+activate fc
+
+create fd
+fc->fd ++: new
+
+return directory:FlashcardDirectory()
+
+destroy fd
+
+create fs
+fc->fs ++: FlashcardStorage(directory)
+
+return : FlashcardStorage
+
+fc->fs++ : loadFlashcards()
+
+alt default
+
+create fl
+fs->fl ++: FlashcardList()
+
+return :FlashcardList
+
+
+
+ loop for all lines in file
+
+ fs->fp++ : loadFlashcard()
+
+ return flashcard:Flashcard
+
+ fs->fl ++: add(flashcard)
+ return
+
+ end
+
+ return :FlashcardList
+
+else FileNotFoundException
+
+
+ fs-->fc
+ create fl2
+ fc->fl2 ++: FlashcardList(emptyArray)
+ return :FlashcardList
+
+
+
+end
+
+@enduml
\ No newline at end of file
diff --git a/docs/Diagrams/flashcard-diagrams/command_package_classes.puml b/docs/Diagrams/flashcard-diagrams/command_package_classes.puml
new file mode 100644
index 0000000000..577525bbda
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/command_package_classes.puml
@@ -0,0 +1,29 @@
+@startuml
+
+hide circle
+skinparam classAttributeIconSize 0
+
+class CreateFlashcardCommand
+class DeleteAllFlashcardsCommand
+class DeleteFlashcardCommand
+abstract class DualFlashcardCommand {
+ + execute(scanner: Scanner, flashcardList: FlashcardList): void
+ # {abstract} executeBeginnerMode(scanner: Scanner, flashcardList: FlashcardList): void
+ # {abstract} executeBeginnerMode(scanner: Scanner, flashcardList: FlashcardList): void
+}
+abstract class FlashcardCommand {
+ + {abstract} execute(scanner: Scanner, flashcardList: FlashcardList): void
+}
+class ListFlashcardsCommand
+class StartReviewCommand
+class UnknownCommand
+
+CreateFlashcardCommand -[#000082,plain]-^ FlashcardCommand
+DeleteAllFlashcardsCommand -[#000082,plain]-^ FlashcardCommand
+DeleteFlashcardCommand -[#000082,plain]-^ DualFlashcardCommand
+DualFlashcardCommand -[#000082,plain]-^ FlashcardCommand
+ListFlashcardsCommand -[#000082,plain]-^ FlashcardCommand
+StartReviewCommand -[#000082,plain]-^ DualFlashcardCommand
+UnknownCommand -[#000082,plain]-^ FlashcardCommand
+
+@enduml
diff --git a/docs/Diagrams/flashcard-diagrams/command_package_classes.svg b/docs/Diagrams/flashcard-diagrams/command_package_classes.svg
new file mode 100644
index 0000000000..78f5ffe830
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/command_package_classes.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/Diagrams/flashcard-diagrams/overview_classes.png b/docs/Diagrams/flashcard-diagrams/overview_classes.png
new file mode 100644
index 0000000000..013b8c01ed
Binary files /dev/null and b/docs/Diagrams/flashcard-diagrams/overview_classes.png differ
diff --git a/docs/Diagrams/flashcard-diagrams/overview_classes.puml b/docs/Diagrams/flashcard-diagrams/overview_classes.puml
new file mode 100644
index 0000000000..7d78a68354
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/overview_classes.puml
@@ -0,0 +1,62 @@
+@startuml
+
+hide circle
+skinparam classAttributeIconSize 0
+
+
+class Flashcard {
+ - backText: String
+ - difficulty: int
+ - frontText: String
+ - {static} globalMaxId: int
+ - id: int
+ + applyDifficultyChange(difficultyChange: int): void
+ + calculateAndUpdateGlobalMaxId(flashcardList: FlashcardList): void
+ + getBackText(): String
+ + getDifficulty(): int
+ + getFrontText(): String
+ + getId(): int
+ + setDifficulty(difficulty: int): void
+ + setId(id: int): void
+ + toString(): String
+}
+
+class FlashcardCommandParser {
+ + parseInput(input: String, calendar: Calendar): FlashcardCommand
+}
+
+class FlashcardComponent {
+ - calendar: Calendar
+ - storage: FlashcardStorage
+ + getFlashcardList(): FlashcardList
+ + getStorage(): FlashcardStorage
+ + getUi(): FlashcardUi
+ + isResponsible(input: String): boolean
+ + processInput(input: String): void
+}
+
+class FlashcardList {
+ + add(flashcard: Flashcard): void
+ + deleteAllFlashcards(): void
+ + deleteFlashcardById(flashcardId: int): boolean
+ + getFlashcards(): ArrayList
+ + getSize(): int
+ + isEmpty(): boolean
+}
+
+class FlashcardUi {
+ - scanner: Scanner
+ + executeCommand(command: FlashcardCommand): void
+ + setScanner(scanner: Scanner): void
+}
+
+
+FlashcardComponent o--> "1" FlashcardList : flashcardList
+FlashcardComponent o--> "1" FlashcardCommandParser : parser
+FlashcardComponent o--> "1" FlashcardUi : ui
+
+FlashcardUi o--> "1" FlashcardList : flashcardList
+
+FlashcardList o--> "*" Flashcard : flashcards
+
+@enduml
diff --git a/docs/Diagrams/flashcard-diagrams/overview_classes.svg b/docs/Diagrams/flashcard-diagrams/overview_classes.svg
new file mode 100644
index 0000000000..0fe441b6ab
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/overview_classes.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/Diagrams/flashcard-diagrams/overview_sequence.puml b/docs/Diagrams/flashcard-diagrams/overview_sequence.puml
new file mode 100644
index 0000000000..9d982c41d6
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/overview_sequence.puml
@@ -0,0 +1,73 @@
+@startuml
+
+hide footbox
+
+actor Actor as user
+participant ":Duke" as duke
+participant ":FlashcardComponent" as component
+participant ":FlashcardCommandParser" as parser
+participant ":FlashcardUi" as ui
+
+user -> duke : list flashcards
+activate duke
+
+duke -> component : isResponsible("list flashcards")
+activate component
+
+component -> parser : parseInput("list flashcards", calendar)
+activate parser
+
+participant "lfc1:ListFlashcardsCommand" as lfc1
+
+create lfc1
+
+parser -> lfc1
+activate lfc1
+
+lfc1 --> parser : lfc1
+deactivate lfc1
+
+parser --> component : lfc1
+deactivate parser
+
+component --> duke : true
+deactivate component
+
+duke -> component : processInput("list flashcards")
+activate component
+
+component -> parser : parseInput("list flashcards", calendar)
+activate parser
+
+participant "lfc2:ListFlashcardsCommand" as lfc2
+
+create lfc2
+
+parser -> lfc2
+activate lfc2
+
+lfc2 --> parser : lfc2
+deactivate lfc2
+
+parser --> component : lfc2
+deactivate parser
+
+component -> ui : executeCommand(lfc2)
+activate ui
+
+ui -> lfc2 : execute(scanner, flashcardList)
+activate lfc2
+
+lfc2 --> ui
+deactivate lfc2
+
+ui --> component
+deactivate ui
+
+component --> duke
+deactivate component
+
+duke --> user
+deactivate duke
+
+@enduml
diff --git a/docs/Diagrams/flashcard-diagrams/overview_sequence.svg b/docs/Diagrams/flashcard-diagrams/overview_sequence.svg
new file mode 100644
index 0000000000..ec740c204e
--- /dev/null
+++ b/docs/Diagrams/flashcard-diagrams/overview_sequence.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..875d536931 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,10 @@
-# Duke
+# TaskLinker
-{Give product intro here}
+TaskLinker is a CLI-tool for helping university students memorize flashcards
+and track their flashcard and general academic progress in the courses they are
+taking.
-Useful links:
-* [User Guide](UserGuide.md)
-* [Developer Guide](DeveloperGuide.md)
-* [About Us](AboutUs.md)
+Get started by reading the following guidelines:
+* Read the [User Guide](UserGuide.md) if you are a user.
+* Read the [Developer Guide](DeveloperGuide.md) if you are a developer.
+* Read the [About Us](AboutUs.md) section to learn about the developer team.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..b930ae9004 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,549 @@
-# User Guide
+# **User Guide**
-## Introduction
+## **Introduction**
-{Give a product intro}
+TaskLinker is a CLI-tool for helping university students memorize flashcards
+and track their flashcard progress as well as general academic progress in
+the courses they are taking.
-## Quick Start
-
-{Give steps to get started quickly}
+## **Quick Start**
1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+2. Download the latest jar from [the latest release on GitHub](https://github.com/AY2324S1-CS2113-F11-3/tp/releases).
+3. Run the jar file via `java -jar duke.jar`
+
+## **Features**
+
+### **Notes about the command format and sample output format:**
+
+#### **Command format**
+
+In the command format, words in UPPER_CASE are the parameters to be
+supplied by the user. e.g. in `delete flashcard FLASHCARD_ID`, FLASHCARD_ID
+is a parameter whose value shall be supplied by the user, e.g. as `delete
+flashcard 3`.
+
+#### **Sample output format**
+
+When sample output is provided, it is shown as a code block.
+
+User input within the example is shown in bold, text printed by the program
+is shown in normal thickness.
+
+E.g. in the following example, the user inputted the command "list
+flashcards" and the program printed out a list of the available flashcards.
+
+Enter your command: list flashcards
+ Here is a list of all your flashcards:
+
+--------------------------------------------------------------------------------
+front text: How long is a meter in cm?
+back text: 100
+id: 20
+difficulty: 4
+--------------------------------------------------------------------------------
+front text: What does UML stand for?
+back text: Unified Modelling Language
+id: 21
+difficulty: 6
+--------------------------------------------------------------------------------
+
+ Those were all your flashcards.
+
+
+### **Flashcard-related features**
+
+#### **General explanation of flashcards**
+
+Flashcards are two-sided cards that have a question on the front and its
+answer on the back. They are used for revising information and helping with
+memorization. As such, they are often used by students; e.g. medicine students often use
+flashcards to memorize the anatomy of the human body.
+
+TaskLinker implements virtual flashcards that you can create, review and
+delete on the go, without being bound to physical copies.
+
+In TaskLinker, every flashcard has a front text (the question) and a back
+text (the answer). Also, every flashcard has a difficulty attribute that shows
+how hard it is for you to remember this particular flashcard (The higher the
+difficulty number, the harder). Every flashcard is identified by a unique id
+(Flashcard ids don't necessarily start at zero and are not necessarily
+consecutive. Don't worry, this is totally fine and the planned behavior!).
-## Features
+#### **"Dual Commands": Different input options for beginner vs expert users**
-{Give detailed description of each feature}
+We know that not all users want the same. Same want more simplicity, whilst
+others want more sophisticated tools that speed up their working speed.
+To cater to both groups of users, TaskLinker's flashcards features offer
+so-called "dual commands" that can be invoked in two different ways: an easy,
+but more time-consuming way for beginner users who want as much guidance as
+possible; or a less time-consuming, but more complicated way for expert users
+who don't need additional guidance.
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+Currently, the following commands are dual commands:
-Format: `todo n/TODO_NAME d/DEADLINE`
+- [`review flashcards`](#reviewing-your-flashcards-review-flashcards)
+- [`delete flashcard`](#deleting-a-flashcard-delete-flashcard)
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+For more information, see the respective sections explaining their usage.
+
+#### **Listing all flashcards: `list flashcards`**
+
+Prints out a list of all flashcards that shows each flashcard's front text
+and back text as well as its id and current difficulty level.
+
+Command Format: `list flashcards`
Example of usage:
+
+Enter your command: list flashcards
+ Here is a list of all your flashcards:
+
+--------------------------------------------------------------------------------
+front text: How long is a meter in cm?
+back text: 100
+id: 20
+difficulty: 4
+--------------------------------------------------------------------------------
+front text: What does UML stand for?
+back text: Unified Modelling Language
+id: 21
+difficulty: 6
+--------------------------------------------------------------------------------
+
+ Those were all your flashcards.
+
+
+#### **Creating a new flashcard: `create flashcard`**
+
+Starts the process of creating a new flashcard.
+
+After entering this command, you are prompted to first input the front page
+text (once you have typed it out, submit it by pressing ENTER) and then the
+back page text (once you have typed it out, submit it by pressing ENTER) of
+your new flashcard.
+
+After you've done this, a success message will be printed out. This
+indicates that your new flashcard has been successfully created and saved.
+
+Command Format: `create flashcard`
+
+Example of usage:
+
+Enter your command: create flashcard
+Enter the front page text: What is a banana?
+Enter the back page text: A kind of fruit
+
+Success! Flashcard has been added to your collection.
+
+
+#### **Reviewing your flashcards: `review flashcards`**
+
+Starts the process of reviewing your flashcards.
+
+The `review flashcards` command is a so-called "Dual Command" that can be
+invoked in two different ways: an easy, but more time-consuming way for
+beginner users who want as much guidance as possible; or a less
+time-consuming, but more complicated way for expert users who don't need
+additional guidance.
+
+There are two review modes to choose from:
+
+- **random mode:** The flashcards to be reviewed are randomly chosen.
+- **spaced repetition mode:** Which flashcards are chosen to be reviewed
+ depends on
+ how well you previously knew their contents. Flashcards which you couldn't
+ remember well are shown more often, while flashcards which you remembered well
+ are shown less often.
+
+How you chose your review mode differs between the beginner mode and expert
+mode:
+
+- **Choosing review mode in beginner mode:** After you've inputted the
+ `review flashcards` command, in a separate step, you are prompted to select
+ your desired review mode by inputting its respective letter: Input `a` to
+ choose random mode, or input `b` to choose spaced repetition mode.
+- **Choosing review mode in expert mode:** You have to already choose the
+ review mode when you input the `review flashcards` command. Thus, you have
+ to use the `review flashcards REVIEW_MODE` format, where REVIEW_MODE has
+ to be either an `a` (for random mode) or a `b` (for spaced repetition mode)
+ . Unlike in the beginner mode, there is no separate step for you to
+ choose a review mode from a list of available options as you have already
+ supplied which review mode you want to use via the REVIEW_MODE parameter
+ of the `review flashcards REVIEW_MODE` command format; thus saving you time.
+
+Once you've selected a review mode, the actual review begins.
+
+Firstly, the front page of a flashcard is shown to you. You should now try and
+think of the answer (the text on the back page of the flashcard); and once
+you're ready, press ENTER to be shown the back page of the flashcard so you can
+compare what you expected to be the answer to the actual answer.
+
+In spaced repetition mode, after you have revealed the back page of a
+flashcard, you are prompted to rate how to difficult it was to remember.
+Select `E` if it was easy, `M` if it was moderately hard and `H` if it was
+quite hard. This information is used to adjust the difficulty of the
+flashcard you just reviewed.
+
+(In random mode, no such process of rating the flashcard's difficulty takes
+place.)
+
+Now, the process repeats and the front page of the next flashcard is shown to
+you.
+
+If you ever want to quit the review process, simply input `q` or `quit` instead
+of pressing ENTER to reveal the back page.
+
+##### **Command format and example of usage in beginner mode**
+
+Command Format: `review flashcards`
+
+Example of usage:
+
+Enter your command: review flashcards
+ How do you want to review your flashcards?
+ a) random mode
+ b) spaced repetition mode
+a
+ You have started a review session in random review mode
+
+ ----------------------------------------------------------------------------
+ The front text is: What is the boiling point of water?
+
+ Think of the answer (the back text) in your head.
+ Press ENTER when you are ready to compare it,
+ or enter q or quit to end this review session.
+
+ The actual back text is: 100 degrees Celsius
+
+ ----------------------------------------------------------------------------
+ The front text is: What is the boiling point of water?
+
+ Think of the answer (the back text) in your head.
+ Press ENTER when you are ready to compare it,
+ or enter q or quit to end this review session.
+quit
+ Success! You have ended this review session.
+
+
+##### **Command format and example of usage in expert mode**
+
+Command Format: `review flashcards REVIEW_MODE` (where REVIEW_MODE has to be
+either an `a` or a `b`)
+
+Example of usage:
+
+Enter your command: review flashcards b
+ You have started a review session in spaced repetition mode
+
+ ----------------------------------------------------------------------------
+ The front text is: What is the boiling point of water?
+
+ Think of the answer (the back text) in your head.
+ Press ENTER when you are ready to compare it,
+ or enter q or quit to end this review session.
+
+ The actual back text is: 100 degrees Celsius
+
+ How hard was it to remember the back page of this flashcard?
+ Input E if it was easy, M if it was moderately challenging
+ or H if it was quite hard.
+H
+ ----------------------------------------------------------------------------
+ The front text is: What is the boiling point of water?
+
+ Think of the answer (the back text) in your head.
+ Press ENTER when you are ready to compare it,
+ or enter q or quit to end this review session.
+q
+ Success! You have ended this review session.
+
+
+#### **Deleting a flashcard: `delete flashcard`**
+
+Starts the process of deleting a flashcard.
+
+The `delete flashcard` command is a so-called "Dual Command" that can be
+invoked in two different ways: an easy, but more time-consuming way for
+beginner users who want as much guidance as possible; or a less
+time-consuming, but more complicated way for expert users who don't need
+additional guidance.
+
+How you chose which flashcard to delete differs between the beginner mode and
+expert mode:
-`todo n/Write the rest of the User Guide d/next week`
+- **Choosing review mode in beginner mode:** After you've inputted the
+ `delete flashcard` command, in a separate step, you are prompted to select
+ the flashcard you want to delete by inputting its id.
+- **Choosing review mode in expert mode:** You have to already choose the
+ flashcard you want to delete when you input the `delete flashcard` command.
+ Thus, you have to use the `delete flashcards FLASHCARD_ID` format, where
+ FLASHCARD_ID is the id of the flashcard you want to delete. Unlike in the
+ beginner mode, there is no separate step for you to choose which flashcard you
+ want to delete as you have already informed TaskLinker about which flashcard
+ you want to delete via the FLASHCARD_ID parameter of the
+ `delete flashcards FLASHCARD_ID` command format; thus saving you time.
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
-## FAQ
+If the id you provided was a valid id, the flashcard with that id is deleted;
+otherwise, an error message is shown, and you are prompted to retry.
+
+##### **Command format and example of usage in beginner mode**
+
+Command format: `delete flashcard`
+
+Example of usage:
+
+Enter your command: delete flashcard
+ Enter id of the flashcard you want to delete: 2
+ Flashcard with id 2 has been successfully deleted.
+
+
+##### **Command format and example of usage in expert mode**
+
+Command format: `delete flashcard FLASHCARD_ID` (where FLASHCARD_ID is the
+id of the flashcard you want to delete)
+
+Example of usage:
+
+Enter your command: delete flashcard 34
+ Couldn't find a flashcard with id 34
+ No deletion has been performed. Please try again with a valid id.
+
+
+#### **Deleting all flashcards: `delete all flashcards`**
+
+Deletes all flashcards currently stored by TaskLinker.
+
+Format: `delete all flashcards`
+
+Example of usage:
+
+Enter your command: delete all flashcards
+ All your flashcards have been successfully deleted.
+
+
+### **Calendar-related features**
+
+#### **General explanation of flashcards**
+
+TaskLinker's calendar feature allows users to manage their time effectively
+by adding, listing, finding, and deleting events. Events in the calendar have a
+specified start and end time, making it easy for users to plan their schedules.
+This feature is particularly useful for individuals with busy schedules or
+those who want to keep track of their upcoming appointments or tasks.
+
+The TaskLinker is also integrated with the flashcards and can be used for setting
+a goal to review flashcards. Add goal event can be used to take user input for
+setting a goal to review flashcards.
+
+Here is your features list:
+
++ `add event` , `delete event`
++ `list events` , `find event`
++ `delete all events` , `add goal event`
+
+Users can use the above features to handle their events`
+
+#### **Adding an event to the calendar: `add event`**
+
+Adds an event to the calendar with start and end time.
+
+After entering this command, the user is asked to enter the event name on the calendar.
+Once the name is given, the user should press ENTER to continue. Once the name is entered,
+the user is prompted to give a start time and an end time for the event.
+
+The start and the end time should be in an acceptable format (`yyyy-mm-ddThh:mm:ss`.)
+If it is not in an acceptable format, (`Invalid date and time format. Please try again.`)
+message will appear and prompt the user to enter a new start time.
+
+Furthermore, the end time should be later than the start time as an event cannot
+end before it's start time. If an earlier time is given for the end time than the
+start time, the TaskLinker displays (`End time is before or equal to the start time. Please enter the correct end time.`)
+message and starts over from (`Enter your command:`).
+
+Format:
+
+Enter your command: add event
+What's the event?: Name [Event Name]
+When does it start?: yyyy-mm-ddThh:mm:ss [Start Time]
+When does it end?: yyyy-mm-ddThh:mm:ss [End Time]
+
+
+Example of usage:
+
+Enter your command: add event
+What's the event?: Do HW
+When does it start?: 2023-12-20T12:30:30
+When does it end?: 2023-12-20T13:40:30
+
+Event 'Do HW' From: 2023-12-20T12:30:30, To: 2023-12-20T13:40:30
+has been added to your Calendar
+
+
+#### **Adding a goal event to the calendar: `add goal event`**
+
+Adds a goal of reviewing flashcards as an event to the calendar.
+
+After entering (`add goal event`) command, the user is asked to provide a name
+for this goal event. After the name, the user is prompted to give an end time
+for the event. The end time serves as a deadline for the goal.
+
+After the deadline has been given, then the goal should be given. Goal of reviewing
+some number of flashcards by the given deadline. Same as adding an event, if an unacceptable
+format of end time is given, the TaskLinker will display (`Invalid date and time format. Please try again.`)
+message.
+
+Format:
+
+Enter your command: add goal event
+What's the event?: Name [Goal Name]
+When does it end?: yyyy-mm-ddThh:mm:ss [End Time]
+How many flashcard to review by then?: Number [# of flashcards to review]
+
+
+Example of usage:
+
+Enter your command: add goal event
+What's the event?: Do Flashcards
+When does it end?: 2023-12-20T12:30:30
+How many flashcard to review by then?: 20
+
+Goal 'Do Flashcards' review 20 flashcards by: 2023-12-20T12:30:30 (Reviewed: 0)
+has been added to your Calendar
+
+
+#### **Delete an event from the calendar: `delete event`**
+
+Deletes an event from the calendar with event name.
+
+After the (`delete event`) command has been given, the user is prompted to give
+the name of the event he/she wants to delete from the calendar. If the given
+event exist in the calendar, then TaskLinker will display (`[Event Name] has been deleted from your Calendar!`).
+Then the event gets deleted from the event list.
+
+However, if the given event name doesn't exist in the calendar. Then the event
+doesn't exist in the calendar message will display (`[Event Name] doesn't exist in your Calendar!`).
+The user then enter a different command.
+
+Format:
+
+Enter your command: delete event
+What's the event?: Name [Event Name]
+ [Event Name] has been deleted from your Calendar!
+
+
+Example of usage:
+
+Enter your command: delete event
+What's the event?: hello
+ hello has been deleted from your Calendar!
+
+
+#### **Delete all events from the Calendar: `delete all events`**
+
+Deletes all events from the calendar.
+
+Once the (`delete all events`) command has been given by the user,
+the TaskLinker will clear all events in the calendar. If the exact
+command is not entered, the feature will not work.
+
+Format & Example:
+
+Enter your command: delete all events
+ All your events have been successfully deleted from the Calendar.
+
+
+#### **Find an event from the Calendar: `find event`**
+
+Finds an event from the calendar.
+
+Once the (`find event`) command has been entered, the user is prompted to
+give the name of the event he/she is looking for. The input user gives can
+just be partial name of the event. If so, the feature will list all
+events that included the given input.
+
+However, if the given input is not found from the events in the Calendar,
+then the (`No such event found`) message will be displayed.
+
+Format:
+
+Enter your command: find event
+What's the event?: Name [Event Name]
+1. Event 'Event Name' From: yyyy-mm-ddThh:mm:ss, To: yyyy-mm-ddThh:mm:ss
+ These events have been found
+
+
+Example of usage:
+
+Enter your command: find event
+What's the event?: Do HW
+1. Event 'Do HW' From: 2023-12-20T12:30:30, To: 2023-12-20T13:30:30
+ These events have been found
+
+
+#### **List all events from the Calendar: `list events`**
+
+Lists all events from the calendar
+
+Once the (`list events`) command has been entered, the TaskLinker lists
+all the events in the event list. If there is no event in the event list,
+the (`The Calendar is empty!`) message will be displayed.
+
+Format & Example:
+
+Enter your command: list events
+ Here is a list of all your events:
+--------------------------------------------------------------------------------
+1. Event 'Do User' From: 2023-12-20T12:30:30, To: 2023-12-20T13:30:30
+--------------------------------------------------------------------------------
+
+
+## **FAQ**
+
+**Q**: Where can I find my flashcard and calendar data?
+
+**A**: You can find it in `data/flashcards` and `data/events` folder.
+
+Every event and flashcard are automatically save after each command.
**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+**A**: You can transfer your data by copying & pasting the data folder.
+
+**Q**: Why is the calendar features needed?
+
+**A**: The calendar features are used for adding a flashcard review and other goals.
+
+**Q**: Are the flashcard and the calendar use different commands?
+
+**A**: Yes, they have different command based on their features.
+
+**Q**: How to exit the program?
-## Command Summary
+**A**: Enter "exit" for the command.
-{Give a 'cheat sheet' of commands here}
+## **Command Summary**
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+* [Listing all flashcards](#listing-all-flashcards-list-flashcards): `list
+ flashcards`
+* [Creating a new flashcard](#creating-a-new-flashcard-create-flashcard):
+ `create flashcard`
+* [Reviewing your flashcards](#reviewing-your-flashcards-review-flashcards):
+ `review flashcards`
+* [Deleting a flashcard](#deleting-a-flashcard-delete-flashcard) `delete
+ flashcard`
+* [Deleting all flashcards](#deleting-all-flashcards-delete-all-flashcards)
+ `delete all flashcards`
+* [Create an event](#adding-an-event-to-the-calendar-add-event):
+ `add event`
+* [Add a goal event](#adding-a-goal-event-to-the-calendar-add-goal-event):
+ `add goal event`
+* [Delete an event](#delete-an-event-from-the-calendar-delete-event):
+ `delete event`
+* [Delete all events](#delete-all-events-from-the-calendar-delete-all-events):
+ `delete all events`
+* [Find an event](#find-an-event-from-the-calendar-find-event):
+ `find event`
+* [List all events](#list-all-events-from-the-calendar-list-events):
+ `list events`
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..a25eb13c93
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: minima
diff --git a/docs/photo/CalendarManagerClassDiagram.drawio.png b/docs/photo/CalendarManagerClassDiagram.drawio.png
new file mode 100644
index 0000000000..18fa82f263
Binary files /dev/null and b/docs/photo/CalendarManagerClassDiagram.drawio.png differ
diff --git a/docs/photo/CalendarManagerSequenceDiagram.drawio.png b/docs/photo/CalendarManagerSequenceDiagram.drawio.png
new file mode 100644
index 0000000000..66ea444eef
Binary files /dev/null and b/docs/photo/CalendarManagerSequenceDiagram.drawio.png differ
diff --git a/docs/photo/FlashcardStorage-0.png b/docs/photo/FlashcardStorage-0.png
new file mode 100644
index 0000000000..337b345b8d
Binary files /dev/null and b/docs/photo/FlashcardStorage-0.png differ
diff --git a/docs/photo/OverallDesign.png b/docs/photo/OverallDesign.png
new file mode 100644
index 0000000000..827b996cdf
Binary files /dev/null and b/docs/photo/OverallDesign.png differ
diff --git a/docs/photo/Screenshot 2023-11-13 at 23.42.45.png b/docs/photo/Screenshot 2023-11-13 at 23.42.45.png
new file mode 100644
index 0000000000..8f1d4f7bb5
Binary files /dev/null and b/docs/photo/Screenshot 2023-11-13 at 23.42.45.png differ
diff --git a/docs/photo/Screenshot 2023-11-13 at 23.44.32.png b/docs/photo/Screenshot 2023-11-13 at 23.44.32.png
new file mode 100644
index 0000000000..368a19ba94
Binary files /dev/null and b/docs/photo/Screenshot 2023-11-13 at 23.44.32.png differ
diff --git a/docs/photo/kherlenbayasgalan.jpg b/docs/photo/kherlenbayasgalan.jpg
new file mode 100644
index 0000000000..fba23dba5b
Binary files /dev/null and b/docs/photo/kherlenbayasgalan.jpg differ
diff --git a/docs/team/brian030601.md b/docs/team/brian030601.md
new file mode 100644
index 0000000000..217c1aee46
--- /dev/null
+++ b/docs/team/brian030601.md
@@ -0,0 +1,83 @@
+# Kherlen Bayasgalan (Brian030601) - Project Portfolio Page
+
+## Overview
+
++ TaskLinker is a CLI-tool for university students to memorize flashcards,
+ review, and track them through their calendar. The calendar can also be
+ used for tracking general events in their normal and academic life.
+
+## Summary of Contributions
+
+### Code contribution
+
+My code contribution can be found in the following link:
+[[Click Here To See] ](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=brian030601&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+I Implemented calendar-related classes and methods listed here: AddEventCommand
+, DeleteAllEventsCommand , DeleteEventCommand , EventCommand , FindEventCommand ,
+ListCalendarEventsCommand , Implemented calendar-related exceptions , EventList, CalendarManager,
+& CalendarCommandParser. I was able to implement those classes based on my
+teammate's architecture. I also implemented exceptions for most of the commands and
+added JavaDoc on each method.
+
+### Contributions to the UG
+
+I wrote around half of the UG. I added the calendar section on UG demonstrating
+the capabilities of the calendar component. I included the format and example cases
+for those features. I also added a Q&A and command summary for the calendar.
+
+**Sections I wrote / added**
++ Wrote the calendar component of the user guide with explanations/examples
++ Added on the Q&A for calendar component
++ Added on command summary for the calendar
+
+### Contributions to the DG
+
+I also wrote half of the DG. I added overall ULM design and additional
+part for the DG. The parts I wrote can be found below:
+
++ Wrote the acknowledgement
++ Drew the overall design UML
++ Wrote the overall design & architecture
++ Wrote calendar component
++ Wrote half of the user stories
++ Wrote the Non-Functional Requirements
++ Wrote the Glossary
++ Wrote the Instructions for manual testing
+
+#### Enhancements implemented
+- **Calendar**
+ - **What it does**: Adds, deletes, finds, and lists events and goals.
+ Handles exceptions to prevent program crash. Integrates flashcard goals
+ for the calendar.
+ - **Justification**: As our team discussed, Calendar is the second main component
+ of the program because we integrate calendar with flashcards. So, implementing
+ calendar was an integral part.
+ - **Enhancements**: In v1.0, only events could be edited. In v2.0, calendar
+ and the flashcards are integrated.
+ - **Highlights**: The implementation took awhile as there was difficult part
+ of integrating two different packages together.
+
+### Review/mentoring contributions
+
++ Reviewed formatting of calendar storage & dual event
++ Reviewed Duke and DukeTest
+
+### Contributions beyond the project team:
+
++ Reviewed and left comments on other team's projects during
+tutorial hours. The links for the evidence can be found [here](/Users/brian/Desktop/Colgate/NUS Fall 2023/CS2113/Team Project/docs/photo/Screenshot 2023-11-13 at 23.42.45.png)
+and [here](/Users/brian/Desktop/Colgate/NUS Fall 2023/CS2113/Team Project/docs/photo/Screenshot 2023-11-13 at 23.44.32.png).
+
+
+### Contributions to team-based tasks
+
+- I came to weekly meetings and contributed to the group through sharing my ideas.
+- I helped update our Google Doc weekly for it to reflect our progress
+- I communicated with other team members on Telegram to discuss and share project
+development and progress.
+- I fixed errors in teammates' codes.
+- I helped create user stories.
+- I set up some issue trackers.
+- Contributed during tutorial questions.
+- I fixed some PE Dry-run team issues.
\ No newline at end of file
diff --git a/docs/team/img.png b/docs/team/img.png
new file mode 100644
index 0000000000..0b73854630
Binary files /dev/null and b/docs/team/img.png differ
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/junhyeong0411.md b/docs/team/junhyeong0411.md
new file mode 100644
index 0000000000..b63687f2ed
--- /dev/null
+++ b/docs/team/junhyeong0411.md
@@ -0,0 +1,50 @@
+# Bang Junhyeong - Project Portfolio Page
+
+## Overview
+
+TaskLinker is a CLI-tool for helping university students memorize flashcards and track their flashcard and general academic progress in the courses they are taking.
+
+### Summary of Contributions
+
+Given below are my contributions to the project.
+
+#### Code contribution
+- You can find the code contribution [here](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code&since=2023-09-22&tabOpen=true&tabType=authorship&tabAuthor=junhyeong0411&tabRepo=AY2324S1-CS2113-F11-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false).
+- Codes for storage and directory
+- Codes for part of calendar and flashcard which is related to storage
+- Added javadoc for storage and directory classes/functions
+
+#### Features
+1. **Save Flashcards** : Automatically saves the changed flashcard data whenever the user enters the command.
+2. **Load Flashcards** : Load the saved flashcards file when program starts
+3. **Save Events** : Automatically saves the changed event data whenever the user enters the command.
+4. **Load Events** : Load the saved events file when program starts
+5. **Make Directories** : When user first start the program, creates the data directories
+6. **Clean up wrong files** : If the saved file has been corrupted, deletes it and make a new file
+
+#### Enhancements implemented
+- **Storage**
+ - **What it does**: It automatically saves the data during the program runs. When the User restarts the program, it automatically retrieves the data. Data is stored along a specific format as a txt file. If someone forcibly changes the data and goes against the format, notify the user and create a new file.
+ - **Justification**: The storage function is essential because the User cannot always turn on the program. Now, users can edit their flashcard and events lists at any time. In addition, the process of inspecting data files is essential because damage may occur in the process of moving or opening them.
+ - **Enhancements**: In v1.0, only flashcards were saved, and the format was simple. In v2.0, events are also saved, and flashcard and events directory were splited. Also, the saving format kept changed because the structure of flashcard and events were changed according to the degree of implementation.
+ - **Highlights**: It was difficult to maintain the developement of storage code because the format of the stored data had to be continuously changed.
+
+#### Contributions to the UG
+[User Guide](https://ay2324s1-cs2113-f11-3.github.io/tp/UserGuide.html)
+- Contributed for Q&A session about storage
+- Gave an explanation how to move the data to other computers
+
+#### Contributions to the DG:
+[Developer Guide](https://ay2324s1-cs2113-f11-3.github.io/tp/DeveloperGuide.html)
+- Described about FlashcardStorage and EventStorage classes.
+- Added Sequance Diagram for FlashcardStorage
+
+#### Contributions to team-based tasks
+- Participated weekly team meeting
+- Found errors in teammates' code and let them know
+- Found errors in teammates' code and fixed it (eg. calculating globalMaxId for flashcard)
+- Post some issues about bugs
+
+#### Review/mentoring contributions
+- Reviewed some PRs and added comments
+- Summarized and delivered the TA's instructions for the team members who couldn't hear it.
diff --git a/docs/team/wendelinwemhoener.md b/docs/team/wendelinwemhoener.md
new file mode 100644
index 0000000000..51aeddbb40
--- /dev/null
+++ b/docs/team/wendelinwemhoener.md
@@ -0,0 +1,137 @@
+# Wendelin Wemhoener - Project Portfolio Page
+
+## Overview
+
+TaskLinker is a CLI-tool for helping university students memorize flashcards
+and track their flashcard and general academic progress in the courses they are
+taking.
+
+## Summary of Contributions
+
+### Code Contribution
+
+See my code contribution [here on the tP Code Dashboard](https://nus-cs2113-ay2324s1.github.io/tp-dashboard/?search=wendelinwemhoener&breakdown=true).
+
+I implemented the `flashcard` package and coded all flashcard-related
+features (except for storing the flashcards in a text file for persistence).
+
+I came up with the architecture of having a separate Parser and Ui component
+that work together to process input and create commands from a `command`
+subpackage that consists of the different commands inheriting from either a
+normal `Command` or `DualCommand` abstract class.
+
+After I had developed this architecture for the `flashcard` package, the
+other team members copied my architecture and reused it for the `calendar`
+package. Also, in many cases, they reused my source code: e.g. the source code
+of `DualEventCommand.java` in the `calendar.command` package is basically a
+perfect copy of the `DualFlashcardCommand.java` class I created in my
+`flashcard.command` package.
+
+To make understanding my code and architecture easier, I wrote Javadoc for all
+the classes and methods (excluding getters, setters and constructors) I
+developed.
+
+In total, I implemented 1241 lines of functional code, thus accounting for more
+than 44% of functional code produced by the entire team.
+
+Also, I ensured that the build process runs without errors and that the
+text-ui-test passes.
+
+Additionally, I implemented tests for the `flashcard` package and achieved
+100% class coverage with my tests, see here:
+![img.png](img.png)
+
+#### Enhancements implemented
+
+- **Flashcards**
+ - **What it does**: Gives the ability to create, delete, list, and review
+ user-generated flashcards. Spaced repetition review mode allows even
+ more efficient studying than analog flashcards because more difficult
+ flashcards are automatically shown more often until, while easier
+ flashcards are shown fewer times. Handles invalid user input and other
+ potentially occuring exceptions to prevent program crash and allow for
+ graceful recovery. So-called "dual commands" give users the ability to
+ choose between entering commands in an easier, but more time-consuming way
+ (for beginner users who want as much guidance as possible) or in a less
+ time-consuming, but more complicated way (for expert users who don't need
+ additional guidance).
+ - **Justification**: Flashcards are first feature we thought of and agreed
+ upon when we planned out TaskLinker. The efficient use of flashcards is
+ the main value proposition of our app and greatly influenced our target
+ user profile. As such, flashcards are the primary component of TaskLinker.
+ - **Highlights**: Integrating "dual commands" and ensuring that the
+ program could process the different syntax for beginner and expert mode
+ without duplicating code was challenging, but using inheritance and
+ abstract base classes allowed me to find a neat solution.
+
+### Contributions to the UG
+
+I documented all flashcard-related features: I documented each single
+command with a description, command format and a usage example and
+additionally wrote an explanation about what flashcards are and what the
+"dual commands" are.
+
+Also, I implemented a structure and formatting that the other team members
+reused.
+
+Moreover, I wrote parts of the UG that are not specific to a feature: I
+wrote the "Introduction", "Quick Start" and "Notes about the command format and
+sample output format" sections and started the "Command Summary".
+
+In total, I wrote 335 lines of the UG, thus accounting for over 60% of the
+entire user guide.
+
+All in all, the sections written by me are:
+
+- "Introduction"
+- "Quick Start"
+- "Notes about the command format and sample output format"
+- "Flashcard-related features"
+- part of "Command Summary"
+
+### Contributions to the DG
+
+I documented all flashcard-related features.
+
+I created three UML diagrams to visualize the structure of the `flashcards`
+package (two class diagrams and one sequence diagram); thus accounting for
+about 43% of UML diagrams in the developer guide.
+
+I also wrote all the flashcard-related user stories.
+
+All in all, the sections written by me are:
+
+- "`flashcard` package" section with all its subsections: "Package structure
+ overview", "Rough control flow overview", "`flashcard.command` package",
+ "`flashcard.exceptions` package" and "`flashcard.review` package" subsections
+- "Target user profile"
+- "Value proposition"
+- part of "User Stories"
+
+### Contributions to team-based tasks
+
+- I set up the GitHub team org, created the project board on GitHub and set
+ up the "developers" team on GitHub
+- I set up the repo and set up GitHub Pages
+- I set up the issue tracker
+- I was responsible for release management (as well as setting up milestones)
+- I documented target user profile and value proposition in UG/DG
+- I set up the Google Doc we used for coordinating the project in the
+ initial phase and kept it updated with the ongoing changes
+- I set up and administrated our Telegram chat group to allow for
+ efficient communication
+- I created the majority of user stories for the DG
+- I coordinated the weekly meetings
+
+### Review/mentoring contributions:
+
+Helped my team members with the tasks during the tutorial.
+
+Reviewed team members' code for style guide violations and gave them
+feedback on it (or fixed it myself for them).
+
+### Contributions beyond the project team
+
+I have created multiple forum posts to clarify questions and allow others to
+also profit from the answers. I currently sit at spot 8 on the forum
+activities dashboard, see [link](https://nus-cs2113-ay2324s1.github.io/dashboards/contents/forum-activities.html).
diff --git a/docs/team/zhujingxi.md b/docs/team/zhujingxi.md
new file mode 100644
index 0000000000..df843e6fc2
--- /dev/null
+++ b/docs/team/zhujingxi.md
@@ -0,0 +1,26 @@
+# Zhu Jingxi - Project Portfolio Page
+
+## Overview
+
+TaskLinker is a CLI-tool for helping university students memorize flashcards and track their
+flashcard and general academic progress in the courses they are taking.
+
+### Summary of Contributions
+
+Given below are my contributions to the project.
+
+#### Code contribution
+- Skeleton classes for event package (Calendar, CalendarCommandParser, CalendarManager, CalendarUi, Event, EventList).
+- Implementation of Goal class and goal flashcard counting capabilities through Calendar class.
+
+#### Features
+1. Implemented goal event adding function for flashcard review recording.
+
+#### Enhancements implemented
+- Implemented dual input mode (beginner and expert) capabilities for event commands.
+
+#### Contributions to the DG
+- Added Class and Sequence Diagram for calendar package and CalendarManager respectively.
+
+#### Contributions to team-based tasks
+- Participated and contributed to weekly team meeting
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
index 5c74e68d59..f1e648b292 100644
--- a/src/main/java/seedu/duke/Duke.java
+++ b/src/main/java/seedu/duke/Duke.java
@@ -1,21 +1,84 @@
+//@@author wendelinwemhoener
+
package seedu.duke;
+import seedu.duke.calendar.Calendar;
+import seedu.duke.calendar.CalendarManager;
+import seedu.duke.flashcard.FlashcardComponent;
+
+import java.util.ArrayList;
import java.util.Scanner;
public class Duke {
+ public Duke() {}
+
+ public static void main(String[] args) {
+ new Duke().run();
+ }
+
/**
- * Main entry-point for the java.duke.Duke application.
+ * Starts a REPL session where commands are inputted and then processed.
*/
- 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());
+ private void run() {
+ Calendar calendar = new Calendar();
+ FlashcardComponent fc = new FlashcardComponent(calendar);
+ CalendarManager cm = new CalendarManager(calendar, new ArrayList<>());
+
+ Scanner scanner = new Scanner(System.in);
+ String input;
+ boolean shouldTerminate = false;
+
+ while (!shouldTerminate) {
+ System.out.print("Enter your command: ");
+ input = scanner.nextLine();
+
+ if (fc.isResponsible(input)) {
+ fc.processInput(input);
+ continue;
+ } else if (cm.isResponsible(input)) {
+ cm.processInput(input);
+ continue;
+ }
+
+ if (input.toLowerCase().strip().equals("exit")) {
+ System.out.println(" You are exiting TaskLinker! Bye!");
+ break;
+ } else if (input.toLowerCase().strip().equals("help")) {
+ printHelp();
+ } else {
+ System.out.println(" Invalid command! Please try again.");
+ }
+ }
+ }
+
+
+ private void printHelp() {
+ System.out.println(" If you need help, please consult our " +
+ "user guide at https://ay2324s1-cs2113-f11-3.github" +
+ ".io/tp/UserGuide.html");
+ System.out.println();
+ System.out.println(" Here is a quick overview over all available " +
+ "commands: ");
+
+ String[] commandFormats = new String[] {
+ "list flashcards",
+ "create flashcard",
+ "review flashcards",
+ "delete flashcard",
+ "delete all flashcards",
+ "help",
+ "add event",
+ "add goal event",
+ "delete event",
+ "delete all events",
+ "find event",
+ "list events",
+ "exit",
+ };
+
+ for (String commandFormat : commandFormats) {
+ System.out.println(" - " + commandFormat);
+ }
}
}
+
diff --git a/src/main/java/seedu/duke/calendar/Calendar.java b/src/main/java/seedu/duke/calendar/Calendar.java
new file mode 100644
index 0000000000..9b6c01e163
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/Calendar.java
@@ -0,0 +1,26 @@
+//@@author Cheezeblokz
+
+package seedu.duke.calendar;
+
+public class Calendar {
+ /**
+ * The class is here for integrating Flashcard goals with the Calendar.
+ * Any other features related to the Calendar can be added here in the future.
+ */
+ EventList eventList;
+
+ public Calendar() {
+ }
+
+ public void setEventList(EventList eventList) {
+ this.eventList = eventList;
+ }
+
+ public void incrementFlashcardCount() {
+ for(Event event : eventList.getEvents()) {
+ if (event.getClass() == Goal.class) {
+ ((Goal) event).flashcardCompleted();
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/CalendarCommandParser.java b/src/main/java/seedu/duke/calendar/CalendarCommandParser.java
new file mode 100644
index 0000000000..3e5e3b59ff
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/CalendarCommandParser.java
@@ -0,0 +1,105 @@
+//@@author Brian030601
+
+package seedu.duke.calendar;
+
+import seedu.duke.calendar.command.AddEventCommand;
+import seedu.duke.calendar.command.AddGoalEventCommand;
+import seedu.duke.calendar.command.DeleteEventCommand;
+import seedu.duke.calendar.command.EventCommand;
+import seedu.duke.calendar.command.FindEventCommand;
+import seedu.duke.calendar.command.DeleteAllEventsCommand;
+import seedu.duke.calendar.command.ListCalendarEventsCommand;
+import seedu.duke.calendar.command.UnknownCommand;
+
+import seedu.duke.calendar.exceptions.AddEventException;
+import seedu.duke.calendar.exceptions.DeleteEventException;
+import seedu.duke.calendar.exceptions.DeleteAllException;
+import seedu.duke.calendar.exceptions.FindEventException;
+import seedu.duke.calendar.exceptions.ListEventException;
+
+import java.util.Scanner;
+
+public class CalendarCommandParser {
+
+ //@@author Brian030601
+ /**
+ * The manageException method is used to throw exceptions if those exceptions have
+ * been encountered. Each if case handles different exception errors. The method
+ * has one parameter (String userInput), which is used to check if the input has
+ * anything else after it.
+ * @param userInput is taken to check if the condition matches the exception.
+ * @throws AddEventException is thrown if the user only inputs add and nothing else.
+ * @throws DeleteEventException is thrown if the user only inputs delete all and nothing else.
+ * @throws DeleteAllException is thrown if the user only inputs delete and nothing else.
+ * @throws FindEventException is thrown if the user only inputs find and nothing else.
+ * @throws ListEventException is thrown if the user only inputs list and nothing else.
+ */
+
+ public static void manageException(String userInput) throws AddEventException, DeleteEventException,
+ DeleteAllException, FindEventException, ListEventException {
+
+ Scanner input = new Scanner(userInput);
+ String command = input.next();
+
+ if (command.equals("add") && !input.hasNext()) {
+ throw new AddEventException();
+ }
+ if (command.equals("delete all") && !input.hasNext()) {
+ throw new DeleteAllException();
+ }
+ if (command.equals("delete") && !input.hasNext()) {
+ throw new DeleteEventException();
+ }
+ if (command.equals("find") && !input.hasNext()) {
+ throw new FindEventException();
+ }
+ if (command.equals("list") && !input.hasNext()) {
+ throw new ListEventException();
+ }
+ }
+
+ //@@author Brian030601
+ /**
+ * The parseInput method is used to catch any exceptions that could occur. The method
+ * has one parameter (String input). The input is used for asserting that it is not null.
+ * If any exceptions are caught, then the corresponding messages are displayed.
+ * Last resort unknown command will run if the command is not recognized.
+ * @param input is used to check whether input is null or not.
+ * @return runs the commands
+ */
+
+ public EventCommand parseInput(String input) {
+ // using asser to check whether the input is null.
+ assert input != null : "input is null";
+
+ try {
+ manageException(input);
+ if (input.startsWith("add event")) {
+ return new AddEventCommand(input);
+ } else if (input.startsWith("add goal event")) {
+ return new AddGoalEventCommand(input);
+ } else if (input.startsWith("delete event")) {
+ return new DeleteEventCommand(input);
+ } else if (input.startsWith("list events")) {
+ return new ListCalendarEventsCommand();
+ } else if (input.startsWith("delete all events")) {
+ return new DeleteAllEventsCommand();
+ } else if (input.startsWith("find event")) {
+ return new FindEventCommand(input);
+ }
+
+ } catch (AddEventException exception) {
+ System.out.println("☹ OOPS!!! The description of an add cannot be empty.");
+ } catch (DeleteAllException exception) {
+ System.out.println("☹ OOPS!!! The description of a delete all cannot be empty.");
+ } catch (DeleteEventException exception) {
+ System.out.println("☹ OOPS!!! The description of a delete cannot be empty.");
+ } catch (FindEventException exception) {
+ System.out.println("☹ OOPS!!! The description of an find cannot be empty.");
+ } catch (ListEventException exception) {
+ System.out.println("☹ OOPS!!! The description of a list cannot.");
+ }
+
+ return new UnknownCommand();
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/CalendarManager.java b/src/main/java/seedu/duke/calendar/CalendarManager.java
new file mode 100644
index 0000000000..0e793b8681
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/CalendarManager.java
@@ -0,0 +1,96 @@
+//@@author Brian030601
+
+package seedu.duke.calendar;
+
+import seedu.duke.calendar.command.EventCommand;
+import seedu.duke.calendar.command.UnknownCommand;
+import seedu.duke.storage.EventDirectory;
+import seedu.duke.storage.EventStorage;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class CalendarManager {
+ Calendar calendar;
+ CalendarUi calendarUi;
+ EventList eventList;
+ CalendarCommandParser calendarCommandParser;
+ Scanner scanner;
+
+ private EventStorage storage;
+
+ /**
+ * The CalendarManager initializes the accesses to other classes.
+ * It also loads events from the storage.
+ * @param events is used to initialize the EventList.
+ */
+
+ public CalendarManager(Calendar calendar, ArrayList events) {
+
+ EventDirectory eventdirectory = new EventDirectory();
+ eventdirectory.listEventFiles();
+
+ storage = new EventStorage(eventdirectory.defaultDirectory());
+
+ try{
+ eventList = storage.loadEvents();
+ } catch (FileNotFoundException e){
+ //System.out.println("Making new file for Events");
+ eventList = new EventList(events);
+ }
+
+ calendar.setEventList(eventList);
+ this.calendar = calendar;
+ calendarUi = new CalendarUi(eventList);
+ calendarCommandParser = new CalendarCommandParser();
+ scanner = new Scanner(System.in);
+
+ }
+
+ // getStorage is used for getting the storage
+ public EventStorage getStorage(){
+ return this.storage;
+ }
+
+ //@@author Brian030601
+ /**
+ * validCommand is used for checking whether the command is valid, and
+ * not an instance of UnknownCommand.
+ * @param input is used for converting the input into command.
+ * @return returns whether the command is instance of UnknownCommand or not.
+ */
+
+ public boolean validCommand(String input) {
+ EventCommand command = calendarCommandParser.parseInput(input);
+
+ return !(command instanceof UnknownCommand);
+ }
+
+ //@@author Brian030601
+ // isResponsible calls the validCommand method.
+ public boolean isResponsible(String input) {
+ return validCommand(input);
+ }
+
+ // processInput is used for saving the events in the EventList.
+ public void processInput(String input) {
+ startCalendar(input);
+
+ storage.saveEvents(eventList.getEvents());
+ }
+
+ //@@author Brian030601
+ /**
+ * startCalender starts the Calendar features and uses the input as a command.
+ * @param input is used for converting the input into command.
+ */
+
+ public void startCalendar(String input) {
+ EventCommand command = calendarCommandParser.parseInput(input);
+ assert !(command instanceof seedu.duke.calendar.command.UnknownCommand) :
+ "Command cannot be " + "unknown";
+ calendarUi.executeCommand(command);
+ //calendarCommandParser.parseInput(command);
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/CalendarUi.java b/src/main/java/seedu/duke/calendar/CalendarUi.java
new file mode 100644
index 0000000000..813a5d83d9
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/CalendarUi.java
@@ -0,0 +1,29 @@
+//@@author Brian030601
+
+package seedu.duke.calendar;
+
+import seedu.duke.calendar.command.EventCommand;
+
+import java.util.Scanner;
+
+public class CalendarUi {
+ private Scanner scanner;
+ private EventList eventList;
+
+ //@@author Brian030601
+ // CalendarUi is the constructor method for CalendarUi class.
+ public CalendarUi (EventList eventList) {
+ scanner = new Scanner(System.in);
+ this.eventList = eventList;
+ }
+
+ //@@author Brian030601
+ /**
+ * executeCommand is used for starting the calendar part of the program.
+ * @param command is used for relaying the command entered by the user.
+ */
+
+ public void executeCommand(EventCommand command) {
+ command.execute(scanner, eventList);
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/Event.java b/src/main/java/seedu/duke/calendar/Event.java
new file mode 100644
index 0000000000..868c5f5bdc
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/Event.java
@@ -0,0 +1,61 @@
+//@@author Brian030601
+
+package seedu.duke.calendar;
+
+import java.time.LocalDateTime;
+
+public class Event {
+ private String name;
+ private LocalDateTime from;
+ private LocalDateTime to;
+
+ //@@author Cheezeblokz
+ // Event is a constructor method for Event class.
+ public Event(String name, LocalDateTime from, LocalDateTime to) {
+ this.name = name;
+ this.from = from;
+ this.to = to;
+ }
+
+ //@@author Cheezeblokz
+ // getName returns the name of the event.
+ public String getName() {
+ return name;
+ }
+
+ // setName is used for setting the event name.
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ // getFrom is used for getting the start time of an Event.
+ public String getFrom() {
+ return from.toString();
+ }
+
+ //@@author Brian030601
+ // setFrom is used for setting the start time of an Event.
+ public void setFrom(LocalDateTime from) {
+ this.from = from;
+ }
+
+ // getFrom is used for getting the end time of an Event.
+ public String getTo() {
+ return to.toString();
+ }
+
+ //@@author Brian030601
+ // setFrom is used for setting the end time of an Event.
+ public void setTo(LocalDateTime to) {
+ this.to = to;
+ }
+
+ // toString is used for formatting the print version of an Event.
+ @Override
+ public String toString() {
+ return "Event '" + name + '\'' +
+ " From: " + from +
+ ", To: " + to;
+ }
+
+}
diff --git a/src/main/java/seedu/duke/calendar/EventList.java b/src/main/java/seedu/duke/calendar/EventList.java
new file mode 100644
index 0000000000..d6b183f59e
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/EventList.java
@@ -0,0 +1,67 @@
+//@@author Brian030601
+
+package seedu.duke.calendar;
+
+import java.util.ArrayList;
+
+public class EventList {
+ //@@author Brian030601
+ private ArrayList eventList;
+
+ // EventList is a constructor method
+ public EventList(ArrayList eventList) {
+ this.eventList = eventList;
+ }
+
+ // addEvent is used for adding an event to the EventList.
+ public void addEvent(Event event) {
+ eventList.add(event);
+ }
+
+ // getEvent is used to get an event from the EventList.
+ public ArrayList getEvents() {
+ return eventList;
+ }
+
+ // getSize is used for getting the size of EventList.
+ public int getSize() {
+ return eventList.size();
+ }
+
+ // findEvent is used for finding a specific event from the EventList.
+ public int findEvent(String keyword) {
+ int count = 0;
+ for (Event event: eventList) {
+ if (event.getName().contains(keyword)) {
+ System.out.println((++count) + ". " + event);
+ }
+ }
+
+ return count;
+ }
+
+ // deleteEvent is used for deleting an event from the EventList
+ public int deleteEvent(String name) {
+ int size = eventList.size();
+ if (size > 0) {
+ eventList.removeIf(event -> event.getName().equals(name));
+ } else {
+ System.out.println("The Calendar is empty");
+ }
+
+ return size;
+ }
+
+ // deleteAllEvents is used for deleting all events in the EventList.
+ public void deleteAllEvents() {
+ eventList.clear();
+ }
+
+ // toString formats the print version of EventList.
+ @Override
+ public String toString() {
+ return "EventStorage{" +
+ "events=" + eventList +
+ '}';
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/Goal.java b/src/main/java/seedu/duke/calendar/Goal.java
new file mode 100644
index 0000000000..4b305084fa
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/Goal.java
@@ -0,0 +1,44 @@
+package seedu.duke.calendar;
+
+import java.time.LocalDateTime;
+
+public class Goal extends Event{
+
+ private String name;
+ private LocalDateTime to;
+ private int goal;
+ private int completed;
+
+ public Goal(String name, LocalDateTime to, int goal, int completed) {
+ super(name, null, to);
+ this.name = name;
+ this.to = to;
+ this.goal = goal;
+ this.completed = completed;
+ }
+
+ public int getGoal() {
+ return goal;
+ }
+
+ public Object getCompleted() {
+ return completed;
+ }
+
+ public void flashcardCompleted() {
+ if (LocalDateTime.now().isBefore(to)) {
+ completed += 1;
+ }
+ }
+
+ @Override
+ public String getFrom() {
+ return "null";
+ }
+
+ @Override
+ public String toString() {
+ return "Goal '" + name + '\'' + " review " + goal + " flashcards by: " + to + " (Reviewed: " + completed + ")";
+ }
+
+}
diff --git a/src/main/java/seedu/duke/calendar/command/AddEventCommand.java b/src/main/java/seedu/duke/calendar/command/AddEventCommand.java
new file mode 100644
index 0000000000..c9d8f7f9b5
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/AddEventCommand.java
@@ -0,0 +1,104 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import java.time.LocalDateTime;
+
+import seedu.duke.calendar.Event;
+import seedu.duke.calendar.EventList;
+
+import java.time.format.DateTimeParseException;
+
+import java.util.Scanner;
+
+public class AddEventCommand extends DualEventCommand {
+
+ //@@author Cheezeblokz
+ public AddEventCommand(String input) {
+ this.input = input;
+ beginnerCommandLength = 2;
+ expertCommandLength = 5;
+ syntaxString = "add event EVENT_NAME EVENT_START_DATE (in format yyyy-mm-ddThh:mm:ss) " +
+ "EVENT_END_DATE (in format yyyy-mm-ddThh:mm:ss)";
+ }
+
+ //@@author Brian030601
+ /**
+ * The executeBeginnerMode method is used to add an event to the calendar.
+ * It has two parameters (Scanner, EventList). The EventList is used to add an
+ * event to the list. The scanner is used to get the user's event name input.
+ * The method first takes the event name, then through parseDateTimeInput,
+ * it gets an acceptable date/time from the user. If the user inserts acceptable inputs,
+ * the event will be added. If the user doesn't, either one of DateTimeParseException
+ * or Invalid input exception.
+ * @param scanner is used to get user's event name.
+ * @param eventList is used to add an event to the list.
+ */
+
+ @Override
+ public void executeBeginnerMode(Scanner scanner, EventList eventList) {
+ System.out.print("What's the event?: ");
+ String eventName = scanner.nextLine();
+
+ // checks if the acceptable format is given by the user to prevent program crash
+ LocalDateTime startTime = parseDateTimeInput(scanner,
+ "When does it start? (yyyy-MM-ddTHH:mm:ss) (e.g., 2023-12-20T12:30:30): ");
+ LocalDateTime endTime = parseDateTimeInput(scanner,
+ "When does it end? (yyyy-MM-ddTHH:mm:ss) (e.g., 2023-12-20T12:30:30): ");
+
+ if (endTime.isAfter(startTime)) {
+ Event event = new Event(eventName, startTime, endTime);
+ eventList.addEvent(event);
+ System.out.println(" " + event + " has been added to your Calendar");
+ } else {
+ System.out.println(" End time is before or equal to the start time. Please enter the correct end time.");
+ }
+ }
+
+ //@@author Cheezeblokz
+ @Override
+ protected void executeExpertMode(Scanner scanner, EventList eventList) {
+ String[] commandParts = input.split(" ");
+ String eventName = commandParts[2];
+ try {
+ LocalDateTime startTime = LocalDateTime.parse(commandParts[3]);
+ LocalDateTime endTime = LocalDateTime.parse(commandParts[4]);
+ if (endTime.isAfter(startTime)) {
+ Event event = new Event(eventName, startTime, endTime);
+ eventList.addEvent(event);
+ System.out.println(" " + event + " has been added to your Calendar");
+ } else {
+ System.out.println(" End time is before or equal to the start time. " +
+ "Please enter the correct end time.");
+ }
+ } catch (DateTimeParseException e) {
+ System.out.println(" Invalid date and time format. Please try again.");
+ }
+ }
+
+
+ //@@author Brian030601
+ /**
+ * The parseDateTimeInput takes two parameters (Scanner , String) and through those parameters
+ * the method gets user's input. Using exception handling of LocalDateTime, the user checks if the
+ * input is in correct date/time format. If it is not in the specified "yyyy-MM-ddTHH:mm:ss" format
+ * the method will throw DateTimeParseException. If it is in right format, the method will return
+ * the input when it is called.
+ * @param scanner is used to get user's date/time input.
+ * @param prompt is given to instruct the user on an acceptable date/time format.
+ * @return returns an acceptable time/date input.
+ */
+
+ private LocalDateTime parseDateTimeInput(Scanner scanner, String prompt) {
+ while (true) {
+ System.out.print(prompt);
+ String userInput = scanner.nextLine();
+ try {
+ // checks if the acceptable format is given by the user to prevent program crash
+ return LocalDateTime.parse(userInput);
+ } catch (DateTimeParseException e) {
+ System.out.println(" Invalid date and time format. Please try again.");
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/AddGoalEventCommand.java b/src/main/java/seedu/duke/calendar/command/AddGoalEventCommand.java
new file mode 100644
index 0000000000..6b53506da2
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/AddGoalEventCommand.java
@@ -0,0 +1,99 @@
+//@@author Cheezeblokz
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.Event;
+import seedu.duke.calendar.EventList;
+import seedu.duke.calendar.Goal;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+import java.util.Scanner;
+
+public class AddGoalEventCommand extends DualEventCommand{
+
+ public AddGoalEventCommand(String input) {
+ this.input = input;
+ beginnerCommandLength = 3;
+ expertCommandLength = 6;
+ syntaxString = "add goal event GOAL_NAME GOAL_END_DATE (in format yyyy-mm-ddThh:mm:ss) FLASHCARD_GOAL_NUMBER";
+ }
+
+ @Override
+ public void executeBeginnerMode(Scanner scanner, EventList eventList) {
+ System.out.print("What's the goal event name?: ");
+ String eventName = scanner.nextLine();
+
+ LocalDateTime endTime = parseDateTimeInput(scanner,
+ "What is the deadline? (yyyy-MM-ddTHH:mm:ss) (e.g., 2023-12-20T12:30:30): ");
+ int goal = parseIntegerInput(scanner,
+ "How many flashcard to review by then?: ");
+
+ if (endTime.isAfter(LocalDateTime.now())) {
+ Event event = new Goal(eventName, endTime, goal, 0);
+ eventList.addEvent(event);
+ System.out.println(event + " has been added to your Calendar");
+ } else {
+ System.out.println(" End time is before the current time. Please enter the correct end time.");
+ }
+ }
+
+ //@@author Cheezeblokz
+ @Override
+ protected void executeExpertMode(Scanner scanner, EventList eventList) {
+ String[] commandParts = input.split(" ");
+ String eventName = commandParts[3];
+ try {
+ LocalDateTime endTime = LocalDateTime.parse(commandParts[4]);
+ int goal = Integer.parseInt(commandParts[5]);
+ if (endTime.isAfter(LocalDateTime.now())) {
+ Event event = new Goal(eventName, endTime, goal, 0);
+ eventList.addEvent(event);
+ System.out.println(event + " has been added to your Calendar");
+ } else {
+ System.out.println(" End time is before the current time. Please enter the correct end time.");
+ }
+ } catch (DateTimeParseException e) {
+ System.out.println(" Invalid date and time format. Please try again.");
+ } catch (NumberFormatException e) {
+ System.out.println(" Invalid integer input. Please try again.");
+ }
+ }
+
+ private int parseIntegerInput(Scanner scanner, String prompt) {
+ while (true) {
+ System.out.print(prompt);
+ String userInput = scanner.nextLine();
+ try {
+ // checks if the acceptable format is given by the user to prevent program crash
+ return Integer.parseInt(userInput);
+ } catch (NumberFormatException e) {
+ System.out.println(" Invalid integer input. Please try again.");
+ }
+ }
+ }
+
+ //@@author Brian030601-reused
+
+ /**
+ * The parseDateTimeInput takes two parameters (Scanner , String) and through those parameters
+ * the method gets user's input. Using exception handling of LocalDateTime, the user checks if the
+ * input is in correct date/time format. If it is not in the specified "yyyy-MM-ddTHH:mm:ss" format
+ * the method will throw DateTimeParseException. If it is in right format, the method will return
+ * the input when it is called.
+ * @param scanner is used to get user's date/time input.
+ * @param prompt is given to instruct the user on an acceptable date/time format.
+ * @return returns an acceptable time/date input.
+ */
+ private LocalDateTime parseDateTimeInput(Scanner scanner, String prompt) {
+ while (true) {
+ System.out.print(prompt);
+ String userInput = scanner.nextLine();
+ try {
+ // checks if the acceptable format is given by the user to prevent program crash
+ return LocalDateTime.parse(userInput);
+ } catch (DateTimeParseException e) {
+ System.out.println(" Invalid date and time format. Please try again.");
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/DeleteAllEventsCommand.java b/src/main/java/seedu/duke/calendar/command/DeleteAllEventsCommand.java
new file mode 100644
index 0000000000..e52339b731
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/DeleteAllEventsCommand.java
@@ -0,0 +1,26 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public class DeleteAllEventsCommand extends EventCommand {
+
+ //@@author Brian030601
+ /**
+ * The execute method is used to delete all events from the EventList. The method takes two
+ * parameters (Scanner , EventList). However, scanner is not used here. It's given because
+ * of the abstract class. The EventList is used to clear the list.
+ * @param scanner is not used. Given due to the abstract class
+ * @param eventList is used to delete all events in the EventList.
+ */
+
+ public void execute(Scanner scanner, EventList eventList) {
+ eventList.deleteAllEvents();
+
+ System.out.println(" All your events have been successfully " +
+ "deleted from the Calendar.");
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/DeleteEventCommand.java b/src/main/java/seedu/duke/calendar/command/DeleteEventCommand.java
new file mode 100644
index 0000000000..33ced5a127
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/DeleteEventCommand.java
@@ -0,0 +1,57 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public class DeleteEventCommand extends DualEventCommand {
+
+ public DeleteEventCommand(String input) {
+ this.input = input;
+ beginnerCommandLength = 2;
+ expertCommandLength = 3;
+ syntaxString = "delete event EVENT_NAME";
+ }
+
+ //@@author Brian030601
+ /**
+ * The execute method is used to delete a specified event from the EventList.
+ * It takes two parameters (Scanner , EventList). The method takes in the event name,
+ * then calls the deleteEvent function to search and delete the event.
+ * If the event is not in the EventList, then "event doesn't exist" message will be displayed.
+ * @param scanner is used to get user's desired event to be deleted.
+ * @param eventList is used to delete the specified event from the EventList.
+ */
+
+ @Override
+ protected void executeBeginnerMode(Scanner scanner, EventList eventList) {
+ int size;
+
+ System.out.print("Enter the event name: ");
+ String eventName = scanner.nextLine();
+
+ size = eventList.deleteEvent(eventName);
+ if (size > eventList.getSize()) {
+ System.out.println(" " + eventName + " has been deleted from your Calendar!");
+ } else if (size != 0 && size == eventList.getSize()) {
+ System.out.println(" " + eventName + " doesn't exist in your Calendar!");
+ }
+ }
+
+ //@@author Cheezeblokz
+
+ @Override
+ protected void executeExpertMode(Scanner scanner, EventList eventList) {
+ String[] commandParts = input.split(" ");
+ String eventName = commandParts[2];
+
+ int size = eventList.deleteEvent(eventName);
+ if (size > eventList.getSize()) {
+ System.out.println(" " + eventName + " has been deleted from your Calendar!");
+ } else if (size != 0 && size == eventList.getSize()) {
+ System.out.println(" " + eventName + " doesn't exist in your Calendar!");
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/DualEventCommand.java b/src/main/java/seedu/duke/calendar/command/DualEventCommand.java
new file mode 100644
index 0000000000..5ac9936fd9
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/DualEventCommand.java
@@ -0,0 +1,32 @@
+//@@author wendelinwemhoener-reused
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public abstract class DualEventCommand extends EventCommand {
+ protected int beginnerCommandLength;
+ protected int expertCommandLength;
+ protected String input;
+ protected String syntaxString;
+
+ protected abstract void executeBeginnerMode(Scanner scanner, EventList eventList);
+
+ protected abstract void executeExpertMode(Scanner scanner,
+ EventList eventList);
+
+ public void execute(Scanner scanner, EventList eventList) {
+ String[] commandParts = input.split(" ");
+
+ if (commandParts.length == beginnerCommandLength) {
+ executeBeginnerMode(scanner, eventList);
+ } else if (commandParts.length == expertCommandLength) {
+ executeExpertMode(scanner, eventList);
+ } else {
+ System.out.println(" Invalid syntax! The syntax is '" + syntaxString + "'");
+ System.out.println(" Please try again.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/EventCommand.java b/src/main/java/seedu/duke/calendar/command/EventCommand.java
new file mode 100644
index 0000000000..0c51a49f86
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/EventCommand.java
@@ -0,0 +1,20 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+import java.util.Scanner;
+
+public abstract class EventCommand {
+
+ //@@author Brian030601
+ /**
+ * The execute method is an abstract class that must be implemented by
+ * its children classes. That way, its children will be able to execute
+ * necessary functions.
+ * @param scanner is used to get user's input.
+ * @param eventList is used to access EventList.
+ */
+
+ public abstract void execute(Scanner scanner, EventList eventList);
+}
diff --git a/src/main/java/seedu/duke/calendar/command/FindEventCommand.java b/src/main/java/seedu/duke/calendar/command/FindEventCommand.java
new file mode 100644
index 0000000000..3d5150cd9e
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/FindEventCommand.java
@@ -0,0 +1,60 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public class FindEventCommand extends DualEventCommand {
+
+ //@@author Cheezeblokz
+
+ public FindEventCommand(String input) {
+ this.input = input;
+ beginnerCommandLength = 2;
+ expertCommandLength = 3;
+ syntaxString = "find event EVENT_NAME";
+ }
+
+ //@@author Brian030601
+ /**
+ * The execute method is to search and find an event from the EventList. The method has two
+ * parameters (Scanner , EventList). Scanner takes the name of the event that the user
+ * wants to find. EventList is accessed to search the event from the list. If the given
+ * input or part of it is not in the event list, "no such event" message will be displayed.
+ * @param scanner is used to get user's input on what event to search for.
+ * @param eventList is used to access EventList and find the specified event.
+ */
+
+ @Override
+ protected void executeBeginnerMode(Scanner scanner, EventList eventList) {
+ System.out.print("What event are you looking for?: ");
+ String eventName = scanner.nextLine();
+
+ int count = eventList.findEvent(eventName);
+
+ if (count > 0) {
+ System.out.println(" These events have been found");
+ } else {
+ System.out.println(" No such event found");
+ }
+ }
+
+
+ //@@author Cheezeblokz
+
+ @Override
+ protected void executeExpertMode(Scanner scanner, EventList eventList) {
+ String[] commandParts = input.split(" ");
+ String eventName = commandParts[2];
+
+ int count = eventList.findEvent(eventName);
+
+ if (count > 0) {
+ System.out.println(" These events have been found");
+ } else {
+ System.out.println(" No such event found");
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/ListCalendarEventsCommand.java b/src/main/java/seedu/duke/calendar/command/ListCalendarEventsCommand.java
new file mode 100644
index 0000000000..bd3bf643b4
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/ListCalendarEventsCommand.java
@@ -0,0 +1,41 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.Event;
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public class ListCalendarEventsCommand extends EventCommand{
+
+ //@@author Brian030601
+ /**
+ * The execute method is used to list all the events in the EventList. The method
+ * has two parameters (Scanner , EventList). The scanner doesn't do anything here
+ * but is given due to the abstract class. EventList is used for getting access to
+ * all the events in the list. If the EventList is empty, "The Calendar is empty"
+ * message will be displayed.
+ * @param scanner is not used. Given due to the abstract class
+ * @param eventList is used to access EventList.
+ */
+
+ public void execute(Scanner scanner, EventList eventList) {
+ if (eventList.getSize() > 0) {
+ System.out.println(" Here is a list of all your events: ");
+ printLine();
+
+ int count = 0;
+ for (Event event : eventList.getEvents()) {
+ System.out.println((++count) + ". " + event);
+ printLine();
+ }
+ } else {
+ System.out.println(" The Calendar is empty");
+ }
+ }
+
+ public void printLine() {
+ System.out.println("-".repeat(80));
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/command/UnknownCommand.java b/src/main/java/seedu/duke/calendar/command/UnknownCommand.java
new file mode 100644
index 0000000000..aee329e51b
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/command/UnknownCommand.java
@@ -0,0 +1,23 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.command;
+
+import seedu.duke.calendar.EventList;
+
+import java.util.Scanner;
+
+public class UnknownCommand extends EventCommand{
+
+ //@@author Brian030601
+ /**
+ * The execute method prints an unknown command message when an unknown command
+ * is entered by the user. The two parameters (Scanner , EventList) are not
+ * user by the method. But its there due to the abstract class.
+ * @param scanner is not used. Given due to the abstract class
+ * @param eventList is not used. Given due to the abstract class
+ */
+
+ public void execute(Scanner scanner, EventList eventList) {
+ System.out.println("Unknown command! Please enter a valid command.");
+ }
+}
diff --git a/src/main/java/seedu/duke/calendar/exceptions/AddEventException.java b/src/main/java/seedu/duke/calendar/exceptions/AddEventException.java
new file mode 100644
index 0000000000..198532a4c5
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/exceptions/AddEventException.java
@@ -0,0 +1,11 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.exceptions;
+
+/**
+ * The AddEventException class is used for handling exceptions related with adding an event
+ */
+
+public class AddEventException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duke/calendar/exceptions/DeleteAllException.java b/src/main/java/seedu/duke/calendar/exceptions/DeleteAllException.java
new file mode 100644
index 0000000000..19774f9b3f
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/exceptions/DeleteAllException.java
@@ -0,0 +1,11 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.exceptions;
+
+/**
+ * The DeleteAllException class is used for handling exceptions related with deleting all events.
+ */
+
+public class DeleteAllException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duke/calendar/exceptions/DeleteEventException.java b/src/main/java/seedu/duke/calendar/exceptions/DeleteEventException.java
new file mode 100644
index 0000000000..7e31d988c7
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/exceptions/DeleteEventException.java
@@ -0,0 +1,11 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.exceptions;
+
+/**
+ * The DeleteEventException class is used for handling exceptions related with deleting an event
+ */
+
+public class DeleteEventException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duke/calendar/exceptions/FindEventException.java b/src/main/java/seedu/duke/calendar/exceptions/FindEventException.java
new file mode 100644
index 0000000000..70966985f6
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/exceptions/FindEventException.java
@@ -0,0 +1,11 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.exceptions;
+
+/**
+ * The FindEventException class is used for handling exceptions related with finding an event.
+ */
+
+public class FindEventException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duke/calendar/exceptions/ListEventException.java b/src/main/java/seedu/duke/calendar/exceptions/ListEventException.java
new file mode 100644
index 0000000000..80c3b75502
--- /dev/null
+++ b/src/main/java/seedu/duke/calendar/exceptions/ListEventException.java
@@ -0,0 +1,11 @@
+//@@author Brian030601
+
+package seedu.duke.calendar.exceptions;
+
+/**
+ * The ListEventException class is used for handling exceptions related with listing events.
+ */
+
+public class ListEventException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duke/flashcard/Flashcard.java b/src/main/java/seedu/duke/flashcard/Flashcard.java
new file mode 100644
index 0000000000..64a95e3fc0
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/Flashcard.java
@@ -0,0 +1,100 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard;
+
+/**
+ * Represents a flashcard with its associated front and back text as well as
+ * its id and current difficulty.
+ */
+public class Flashcard {
+ private static int globalMaxId = 1;
+ private String frontText;
+ private String backText;
+ private int id;
+ private int difficulty;
+
+ /**
+ * Instantiates and returns a flashcard with the given front and back text.
+ * Its id and difficulty (which is 5) are automatically set.
+ *
+ * @param frontText The text on the front of the flashcard.
+ * @param backText The text on the back of the flashcard.
+ */
+ public Flashcard(String frontText, String backText) {
+ this.frontText = frontText;
+ this.backText = backText;
+
+ difficulty = 5; // initial difficulty of a flashcard
+
+ globalMaxId += 1;
+ id = globalMaxId;
+
+ assert globalMaxId >= id : "No id must be bigger than globalMaxId";
+ }
+
+ /**
+ * Updates globalMaxId to be greater than the id of all passed flashcards.
+ *
+ * @param flashcardList List of flashcard to calculate the max id over.
+ */
+ public static void calculateAndUpdateGlobalMaxId(
+ FlashcardList flashcardList) {
+ int currentMax = 1;
+
+ for (Flashcard flashcard : flashcardList.getFlashcards()){
+ if (flashcard.getId() > currentMax) {
+ currentMax = flashcard.getId();
+ }
+ }
+
+ globalMaxId = currentMax;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ //@@author junhyeong0411
+ public void setId (int id) {
+ this.id = id;
+ }
+
+ public String getFrontText() {
+ return frontText;
+ }
+
+ public void setDifficulty(int difficulty) {
+ this.difficulty = difficulty;
+ }
+
+ public String getBackText() {
+ return backText;
+ }
+
+
+ //@@author wendelinwemhoener
+ /**
+ * Returns a string representation of this flashcard.
+ *
+ * @return Front and back text as well as id and difficulty.
+ */
+ public String toString() {
+ return "front text: " + frontText + System.lineSeparator()
+ + "back text: " + backText + System.lineSeparator()
+ + "id: " + id + System.lineSeparator()
+ + "difficulty: " + difficulty + System.lineSeparator();
+ }
+
+ /**
+ * Adjusts (increases) the difficulty of this flashcard.
+ *
+ * @param difficultyChange The amount to increase the difficulty by.
+ */
+ public void applyDifficultyChange(int difficultyChange) {
+ difficulty += difficultyChange;
+ }
+
+ public int getDifficulty() {
+ return difficulty;
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java b/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java
new file mode 100644
index 0000000000..990e8e4c69
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/FlashcardCommandParser.java
@@ -0,0 +1,66 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard;
+
+import seedu.duke.calendar.Calendar;
+import seedu.duke.flashcard.command.FlashcardCommand;
+import seedu.duke.flashcard.command.CreateFlashcardCommand;
+import seedu.duke.flashcard.command.ListFlashcardsCommand;
+import seedu.duke.flashcard.command.StartReviewCommand;
+import seedu.duke.flashcard.command.DeleteAllFlashcardsCommand;
+import seedu.duke.flashcard.command.DeleteFlashcardCommand;
+import seedu.duke.flashcard.command.UnknownCommand;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Parses input entered by the user into a FlashcardCommand for further
+ * processing.
+ */
+public class FlashcardCommandParser {
+ private Logger logger;
+
+ /**
+ * Returns the FlashcardCommand corresponding to the passed input.
+ *
+ * @param input The text inputted by the user.
+ * @return The FlashcardCommand corresponding to input
+ */
+ public FlashcardCommand parseInput(String input, Calendar calendar) {
+ assert input != null : "input must not be null";
+
+ logger = Logger.getLogger("FlashcardCommandParser");
+ logger.setLevel(Level.WARNING);
+
+ input = input.toLowerCase().strip();
+
+ logger.log(Level.INFO, "trying to find matching FlashcardCommand");
+
+ if (input.equals("create flashcard")) {
+ return new CreateFlashcardCommand();
+ } else if (input.equals("list flashcards")) {
+ return new ListFlashcardsCommand();
+ } else if (input.startsWith("review flashcards")) {
+ String[] commandParts = input.split(" ");
+
+ if (commandParts[0].equals("review") && commandParts[1].equals(
+ "flashcards")) {
+ return new StartReviewCommand(input, calendar);
+ }
+ } else if (input.equals("delete all flashcards")) {
+ return new DeleteAllFlashcardsCommand();
+ } else if (input.startsWith("delete flashcard")) {
+ String[] commandParts = input.split(" ");
+
+ if (commandParts[0].equals("delete") && commandParts[1].equals(
+ "flashcard")) {
+ return new DeleteFlashcardCommand(input);
+ }
+ }
+
+ logger.log(Level.INFO, "input doesn't match any know command");
+
+ return new UnknownCommand();
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/FlashcardComponent.java b/src/main/java/seedu/duke/flashcard/FlashcardComponent.java
new file mode 100644
index 0000000000..2afdfd978e
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/FlashcardComponent.java
@@ -0,0 +1,100 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard;
+
+import seedu.duke.calendar.Calendar;
+import seedu.duke.flashcard.command.FlashcardCommand;
+import seedu.duke.flashcard.command.UnknownCommand;
+import seedu.duke.storage.FlashcardDirectory;
+import seedu.duke.storage.FlashcardStorage;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Encapsulates all classes needed for the flashcard functionality and
+ * allows access to them via one unified API.
+ */
+public class FlashcardComponent {
+ private FlashcardCommandParser parser;
+ private FlashcardList flashcardList;
+ private FlashcardUi ui;
+ private FlashcardStorage storage;
+ private Calendar calendar;
+
+ //@@author junhyeong0411
+ public FlashcardComponent(Calendar calendar) {
+ parser = new FlashcardCommandParser();
+
+ FlashcardDirectory flashcarddirectory = new FlashcardDirectory();
+ flashcarddirectory.listFlashcardFiles();
+
+ storage = new FlashcardStorage(flashcarddirectory.defaultDirectory());
+ try {
+ flashcardList = storage.loadFlashcards();
+ } catch (FileNotFoundException e){
+ //System.out.println("Making New file for Flashcards");
+ flashcardList = new FlashcardList(new ArrayList<>());
+ }
+
+ Flashcard.calculateAndUpdateGlobalMaxId(flashcardList);
+ ui = new FlashcardUi(flashcardList);
+ this.calendar = calendar;
+ }
+
+ public FlashcardStorage getStorage(){
+ return this.storage;
+ }
+
+ public FlashcardList getFlashcardList(){
+ return this.flashcardList;
+ }
+
+ /**
+ * get FlashcardUi method
+ * for test
+ * @return
+ */
+ public FlashcardUi getUi(){
+ return ui;
+ }
+
+ //@@author wendelinwemhoener
+ /**
+ * Returns if FlashcardComponent is responsible for handling this input.
+ *
+ * @param input The text inputted by the user.
+ * @return Whether FlashcardComponent is responsible for handling the input.
+ */
+ public boolean isResponsible(String input) {
+ assert input != null : "input must not be null";
+
+ FlashcardCommand command = parser.parseInput(input, calendar);
+
+
+ if (command instanceof UnknownCommand) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Processes user input by parsing it and executing the resulting command.
+ *
+ * @param input The text inputted by the user.
+ */
+ public void processInput(String input) {
+ assert input != null : "input must not be null";
+
+ FlashcardCommand command = parser.parseInput(input, calendar);
+ assert !(command instanceof UnknownCommand) : "Command cannot be " +
+ "unknown";
+
+ ui.executeCommand(command);
+
+ //@@author junhyeong0411
+ // save after every commands
+ storage.saveFlashcards(flashcardList.getFlashcards());
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/FlashcardList.java b/src/main/java/seedu/duke/flashcard/FlashcardList.java
new file mode 100644
index 0000000000..a497e85c2e
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/FlashcardList.java
@@ -0,0 +1,98 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Container class for a list of flashcards.
+ * Exposes a simple, unified API for dealing with a list of flashcards.
+ */
+public class FlashcardList {
+ private ArrayList flashcards;
+ private Logger logger;
+
+ /**
+ * Instantiates and returns a FlashcardList holding the passed flashcards.
+ *
+ * @param flashcards The flashcards to be contained by the FlashcardList.
+ */
+ public FlashcardList(ArrayList flashcards) {
+ this.flashcards = flashcards;
+
+ logger = Logger.getLogger("FlashcardUi");
+ logger.setLevel(Level.WARNING);
+ }
+
+ public ArrayList getFlashcards() {
+ return flashcards;
+ }
+
+ /**
+ * Returns the amount of flashcards held by the FlashcardList.
+ *
+ * @return The size of the FlashcardList.
+ */
+ public int getSize(){
+ return flashcards.size();
+ }
+
+ /**
+ * Adds a flashcard to the FlashcardList.
+ *
+ * @param flashcard The flashcard that shall be added.
+ */
+ public void add(Flashcard flashcard) {
+ flashcards.add(flashcard);
+ }
+
+ /**
+ * Deletes all flashcards in the FlashcardList, effectively emptying it.
+ */
+ public void deleteAllFlashcards() {
+ logger.log(Level.INFO, "clearing the list of flashcards");
+
+ flashcards.clear();
+
+ assert flashcards.size() == 0 : "flashcardList should be empty now";
+ }
+
+ /**
+ * Returns whether the FlashcardList contains any flashcards or not.
+ *
+ * @return If the FlashcardList is empty.
+ */
+ public boolean isEmpty() {
+ return flashcards.isEmpty();
+ }
+
+ /**
+ * Attempts to delete a flashcard by the passed id.
+ * If no flashcard with the passed id exists, returns false.
+ *
+ * @param flashcardId The id of the flashcard to delete.
+ * @return Whether the deletion was successful (true if successful).
+ */
+ public boolean deleteFlashcardById(int flashcardId) {
+ logger.log(Level.INFO, "trying to delete flashcard by id");
+
+ int indexToDeleteAt = -1;
+
+ for (int i = 0; i < flashcards.size(); i++) {
+ if (flashcards.get(i).getId() == flashcardId) {
+ indexToDeleteAt = i;
+ }
+ }
+
+ if (indexToDeleteAt == -1) {
+ logger.log(Level.INFO, "deletion was unsuccessful");
+ return false;
+ } else {
+ flashcards.remove(indexToDeleteAt);
+ logger.log(Level.INFO, "successfully deleted flashcard");
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/FlashcardUi.java b/src/main/java/seedu/duke/flashcard/FlashcardUi.java
new file mode 100644
index 0000000000..91891c6200
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/FlashcardUi.java
@@ -0,0 +1,58 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard;
+
+import seedu.duke.flashcard.command.FlashcardCommand;
+
+import java.util.Scanner;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Responsible for interfacing with the user by managing the dispatching of
+ * commands to be executed and show to the user.
+ */
+public class FlashcardUi {
+ private Scanner scanner;
+ private FlashcardList flashcardList;
+ private Logger logger;
+
+ /**
+ * Instantiates and returns a new FlashcardUi.
+ *
+ * @param flashcardList The flashcards to be used for this Ui.
+ */
+ public FlashcardUi(FlashcardList flashcardList) {
+ scanner = new Scanner(System.in);
+
+ assert flashcardList != null : "flashcardList cannot be null";
+ this.flashcardList = flashcardList;
+
+ logger = Logger.getLogger("FlashcardUi");
+ logger.setLevel(Level.WARNING);
+ }
+
+ /**
+ * Executes a command and provides it with the appropriate context.
+ * This context consists of a scanner for handling input and a
+ * FlashcardList to execute actions on.
+ *
+ * @param command The command that shall be executed.
+ */
+ public void executeCommand(FlashcardCommand command) {
+ logger.log(Level.INFO, "executing the command");
+
+ command.execute(scanner, flashcardList);
+
+ logger.log(Level.INFO, "execution of command finished");
+ }
+
+ /**
+ * Set scanner method
+ * for using bytearrayinputstream in test
+ * @param scanner
+ */
+ public void setScanner(Scanner scanner){
+ this.scanner = scanner;
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/CreateFlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/CreateFlashcardCommand.java
new file mode 100644
index 0000000000..e4fe1e366f
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/CreateFlashcardCommand.java
@@ -0,0 +1,66 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * This command allows creating a new flashcard by inputting its front and
+ * back text.
+ */
+public class CreateFlashcardCommand extends FlashcardCommand {
+ /**
+ * Creates a new flashcard.
+ * The user is asked to input the front and back text of the new
+ * flashcard, and then it is added to the flashcardList.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public void execute(Scanner scanner, FlashcardList flashcardList) {
+ assert scanner != null : "Must be a valid Scanner instance";
+ assert flashcardList != null : "Must be a valid FlashcardList " +
+ "instance";
+
+ String frontPageText = getInputUntilNonEmptyString(scanner, "front");
+ String backPageText = getInputUntilNonEmptyString(scanner, "back");
+
+ Flashcard flashcard = new Flashcard(frontPageText, backPageText);
+
+ flashcardList.add(flashcard);
+
+ System.out.println();
+ System.out.println(" Success! Flashcard has been added to your " +
+ "collection.");
+ }
+
+ /**
+ * Gets a user input for a flashcard, making sure that it is non-empty.
+ *
+ * @param scanner To get user input.
+ * @param flashcardSide Which side of the flashcard (front or back) is
+ * targeted.
+ * @return The user input for the specified flashcardSide.
+ */
+ private String getInputUntilNonEmptyString(Scanner scanner,
+ String flashcardSide) {
+ System.out.print(" Enter the " + flashcardSide + " page text: ");
+ String text = scanner.nextLine();
+
+ while (text.strip().equals("")) {
+ System.out.println(" Invalid input! The " + flashcardSide +
+ " text must contain at least one letter or digit!");
+
+ System.out.print(" Enter the " + flashcardSide
+ + " page text: ");
+ text = scanner.nextLine();
+ }
+
+ assert text != null : "Must be a non-null string";
+ assert (!text.strip().equals("")) : "Must be a non-empty string";
+ return text;
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java b/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java
new file mode 100644
index 0000000000..97c782722b
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/DeleteAllFlashcardsCommand.java
@@ -0,0 +1,25 @@
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * This command allows deleting all current flashcards.
+ */
+public class DeleteAllFlashcardsCommand extends FlashcardCommand {
+ /**
+ * Deletes all flashcards from the flashcardList.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public void execute(Scanner scanner, FlashcardList flashcardList) {
+ flashcardList.deleteAllFlashcards();
+
+ System.out.println(" All your flashcards have been successfully " +
+ "deleted.");
+
+ assert flashcardList.isEmpty() : "flashcardList must be empty";
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java
new file mode 100644
index 0000000000..51489ffec9
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/DeleteFlashcardCommand.java
@@ -0,0 +1,112 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.FlashcardList;
+import seedu.duke.flashcard.exceptions.InvalidFlashcardIdException;
+
+import java.util.Scanner;
+
+/**
+ * This command allows deleting a specific flashcard (by its id).
+ */
+public class DeleteFlashcardCommand extends DualFlashcardCommand {
+ public DeleteFlashcardCommand(String input) {
+ this.input = input;
+ beginnerCommandLength = 2;
+ expertCommandLength = 3;
+ syntaxString = "delete flashcard FLASHCARD_ID";
+ }
+
+ /**
+ * Starts an interactive process for deleting a flashcard by its id.
+ * The user is prompted to enter the id; and then it is deleted.
+ *
+ * @param scanner Scanner for getting user input.
+ * @param flashcardList FlashcardList from which to delete.
+ */
+ protected void executeBeginnerMode(Scanner scanner,
+ FlashcardList flashcardList) {
+ assert flashcardList != null : "Must be a valid flashcardList " +
+ "instance";
+
+ System.out.print(" Enter id of the flashcard you want to " +
+ "delete: ");
+
+ String input = scanner.nextLine();
+ int flashcardId;
+
+ try {
+ flashcardId = Integer.parseInt(input);
+ } catch (NumberFormatException e) {
+ System.out.println(" Invalid input! Id must be an integer");
+ return;
+ }
+
+ tryDeleteFlashcardById(flashcardId, flashcardList);
+ }
+
+ /**
+ * Tries to delete a flashcard given its id and prints whether it worked.
+ *
+ * @param flashcardId The id of the flashcard to delete.
+ * @param flashcardList The list of flashcards to operate on.
+ */
+ public void tryDeleteFlashcardById(int flashcardId,
+ FlashcardList flashcardList) {
+ try {
+ deleteFlashcardById(flashcardId, flashcardList);
+ } catch (InvalidFlashcardIdException e) {
+ System.out.println(" Couldn't find a flashcard with id "
+ + flashcardId);
+ System.out.println(" No deletion has been performed. Please "
+ + "try again with a valid id.");
+ }
+ }
+
+ /**
+ * Allows deleting a flashcard whose id has already been inputted.
+ *
+ * @param scanner Scanner for getting user input.
+ * @param flashcardList FlashcardList from which to delete.
+ */
+ protected void executeExpertMode(Scanner scanner,
+ FlashcardList flashcardList) {
+ assert flashcardList != null : "Must be a valid flashcardList " +
+ "instance";
+
+ String[] commandParts = input.split(" ");
+ assert commandParts.length != 0 : "must contain command parts";
+
+ try {
+ int flashcardId = Integer.parseInt(commandParts[2]);
+ tryDeleteFlashcardById(flashcardId, flashcardList);
+ } catch (NumberFormatException e) {
+ System.out.println(" Invalid id! Id must be an integer");
+ }
+ }
+
+ /**
+ * Tries to delete a flashcard by id.
+ *
+ * If the deletion is successful, a success message is printed;
+ * otherwise, an exception is thrown.
+ *
+ * @param flashcardId The id of the flashcard to delete.
+ * @param flashcardList The list of all known flashcards.
+ * @throws InvalidFlashcardIdException if flashcardId is invalid.
+ */
+ private void deleteFlashcardById(int flashcardId,
+ FlashcardList flashcardList)
+ throws InvalidFlashcardIdException {
+ boolean deletionWasSuccessful =
+ flashcardList.deleteFlashcardById(flashcardId);
+
+ if (deletionWasSuccessful) {
+ System.out.println(" Flashcard with id " + flashcardId
+ + " has been successfully deleted.");
+ } else {
+ throw new InvalidFlashcardIdException();
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java
new file mode 100644
index 0000000000..40725061ef
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/DualFlashcardCommand.java
@@ -0,0 +1,81 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * This class allows creating commands that can be invoked in two ways: the
+ * beginner mode or the expert mode.
+ *
+ * The beginner mode interactively prompts the user to enter his data; i.e.
+ * first the user enters the command name, and then the command prompts him
+ * to enter the additional pieces of information required (i.e. which review
+ * mode to choose). Thus, the user is guided through the choices he has to
+ * make.
+ *
+ * The expert mode allows the user to enter all information at once in a
+ * single line. This speeds the process up, but provides the user with less
+ * guidance and is thus harder.
+ *
+ * In order to accommodate for both modes and thus allow users to decide
+ * whether they want to take the slower, but easier approach or rather the
+ * faster, but harder approach, DualFlashcardCommand allows implementing
+ * both modes so that users can simply choose.
+ *
+ * The developer has to implement the executeBeginnerMode and the
+ * executeExpertMode methods to implement beginner mode and expert mode,
+ * respectively.
+ */
+public abstract class DualFlashcardCommand extends FlashcardCommand {
+ protected int beginnerCommandLength;
+ protected int expertCommandLength;
+ protected String input;
+ protected String syntaxString;
+
+ /**
+ * Allows implementing the beginner mode (with interactive input).
+ *
+ * @param scanner To get user input.
+ * @param flashcardList The flashcards to operate on.
+ */
+ protected abstract void executeBeginnerMode(Scanner scanner,
+ FlashcardList flashcardList);
+
+ /**
+ * Allows implementing the expert mode (with one-line input).
+ *
+ * @param scanner To get user input.
+ * @param flashcardList The flashcards to operate on.
+ */
+ protected abstract void executeExpertMode(Scanner scanner,
+ FlashcardList flashcardList);
+
+ /**
+ * Decides whether to use beginner or expert mode and executes it.
+ *
+ * This decision is based on the length of the inputted command: it is
+ * compared to the length of the input for both beginner and expert mode
+ * and then the appropriate method is executed.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public void execute(Scanner scanner, FlashcardList flashcardList) {
+ String[] commandParts = input.split(" ");
+
+ assert commandParts != null : "must contain values";
+
+ if (commandParts.length == beginnerCommandLength) {
+ executeBeginnerMode(scanner, flashcardList);
+ } else if (commandParts.length == expertCommandLength) {
+ executeExpertMode(scanner, flashcardList);
+ } else {
+ System.out.println(" Invalid syntax! The syntax is '"
+ + syntaxString + "'");
+ System.out.println(" Please try again.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/FlashcardCommand.java b/src/main/java/seedu/duke/flashcard/command/FlashcardCommand.java
new file mode 100644
index 0000000000..336d164015
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/FlashcardCommand.java
@@ -0,0 +1,24 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * Abstract class that provides the interface for executing commands by using
+ * a Scanner for input and a FlashcardList to perform actions on as command
+ * execution context.
+ */
+public abstract class FlashcardCommand {
+ /**
+ * Executes a command, given the appropriate context.
+ * This context consists of a scanner for handling input and a
+ * FlashcardList to execute actions on.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public abstract void execute(Scanner scanner, FlashcardList flashcardList);
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java b/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java
new file mode 100644
index 0000000000..3dbc4c7f53
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/ListFlashcardsCommand.java
@@ -0,0 +1,42 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * This command allows listing all current flashcards.
+ */
+public class ListFlashcardsCommand extends FlashcardCommand {
+ /**
+ * Prints out a list of all current flashcards.
+ * Handles the scenario that there are no flashcards by printing an
+ * appropriate "You dont't have any flashcards yet!" message.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public void execute(Scanner scanner, FlashcardList flashcardList) {
+ if (flashcardList.isEmpty()) {
+ System.out.println(" You dont't have any flashcards yet! ");
+ return;
+ }
+
+ assert flashcardList.isEmpty() == false : "must contain flashcards";
+
+ System.out.println(" Here is a list of all your flashcards: ");
+ System.out.println();
+
+ System.out.println("-".repeat(80));
+ for (Flashcard flashcard : flashcardList.getFlashcards()) {
+ System.out.print(flashcard);
+ System.out.println("-".repeat(80));
+ }
+ System.out.println();
+
+ System.out.println(" Those were all your flashcards.");
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java b/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java
new file mode 100644
index 0000000000..ad89ecc66f
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/StartReviewCommand.java
@@ -0,0 +1,145 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.calendar.Calendar;
+import seedu.duke.flashcard.FlashcardList;
+import seedu.duke.flashcard.exceptions.InvalidReviewModeException;
+import seedu.duke.flashcard.review.RandomReviewMode;
+import seedu.duke.flashcard.review.ReviewMode;
+import seedu.duke.flashcard.review.SpacedRepetitionReviewMode;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * This command allows starting a flashcard review by either using beginner
+ * or expert mode.
+ *
+ * Users get to choose from random review mode and spaced repetition review
+ * mode.
+ */
+public class StartReviewCommand extends DualFlashcardCommand {
+ private final ArrayList choices = new ArrayList<>(Arrays.asList(
+ "a", "b"));
+ private Calendar calendar;
+
+ public StartReviewCommand(String input, Calendar calendar) {
+ this.input = input;
+ this.calendar = calendar;
+ beginnerCommandLength = 2;
+ expertCommandLength = 3;
+ syntaxString = "review flashcards REVIEW_MODE";
+ }
+
+ /**
+ * Returns the letter of the review mode chosen by the user.
+ *
+ * @param scanner To get input from the user.
+ * @return The letter entered by the user to choose the review mode.
+ */
+ private String getUserChoiceReviewMode(Scanner scanner) {
+ System.out.println(" How do you want to review your flashcards?");
+ System.out.println(" a) random mode");
+ System.out.println(" b) spaced repetition mode");
+
+ return scanner.nextLine();
+ }
+
+ /**
+ * Starts an interactive process to select and start a review mode.
+ *
+ * The user is asked for the review mode he wants to use; and then the
+ * respective review mode is started.
+ *
+ * @param scanner To get user input.
+ * @param flashcardList The flashcards to operate on.
+ */
+ protected void executeBeginnerMode(Scanner scanner,
+ FlashcardList flashcardList) {
+ assert scanner != null : "Must be valid Scanner instance";
+
+ String choice = getUserChoiceReviewMode(scanner);
+
+ while (!choices.contains(choice.toLowerCase())) {
+ System.out.println(" Invalid choice! Your choice must be a or "
+ + "b! Please try again.");
+
+ choice = getUserChoiceReviewMode(scanner);
+ }
+
+ startReview(scanner, flashcardList, choice);
+ }
+
+ /**
+ * Starts a review session in the review mode inputted by the user.
+ *
+ * The user mode (a or b) is already passed as part of the
+ * one-line-command used to start this review.
+ *
+ * @param scanner To get user input.
+ * @param flashcardList The flashcards to operate on.
+ */
+ protected void executeExpertMode(Scanner scanner,
+ FlashcardList flashcardList) {
+ String[] commandParts = input.split(" ");
+
+ assert commandParts.length > 0 : "must contain values";
+
+ try {
+ String choice = commandParts[2].toLowerCase();
+
+ if (!choices.contains(choice)) {
+ throw new InvalidReviewModeException();
+ }
+
+ startReview(scanner, flashcardList, choice);
+ } catch (InvalidReviewModeException e) {
+ System.out.println(" Invalid choice! Your choice must be a"
+ + " or b! Please try again.");
+ return;
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println(" Invalid syntax! The syntax is 'review " +
+ "flashcards REVIEW_MODE'");
+ System.out.println(" Please try again.");
+ }
+ }
+
+ /**
+ * Starts a flashcard review in the desired mode.
+ *
+ * @param scanner To get user input.
+ * @param flashcardList The flashcards from whom to pick.
+ * @param choice Character indicating the desired review mode.
+ */
+ private void startReview(Scanner scanner,
+ FlashcardList flashcardList,
+ String choice) {
+ ReviewMode reviewMode = createReviewMode(choice.toLowerCase(), flashcardList);
+
+ reviewMode.startReviewSession(scanner, calendar);
+
+ }
+
+ /**
+ * Creates and returns an instance of the desired ReviewMode.
+ *
+ * @param choice Whether it should be random or spaced repetition mode.
+ * @param flashcardList The flashcards on which the review should operate.
+ * @return An instance of the desired review mode.
+ */
+ private ReviewMode createReviewMode(String choice, FlashcardList flashcardList) {
+ ReviewMode reviewMode = null;
+
+ if (choice.equals("a")) {
+ reviewMode = new RandomReviewMode(flashcardList);
+ } else if (choice.equals("b")) {
+ reviewMode = new SpacedRepetitionReviewMode(flashcardList);
+ }
+
+ assert reviewMode != null;
+
+ return reviewMode;
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/command/UnknownCommand.java b/src/main/java/seedu/duke/flashcard/command/UnknownCommand.java
new file mode 100644
index 0000000000..f0458cb658
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/command/UnknownCommand.java
@@ -0,0 +1,22 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.command;
+
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.Scanner;
+
+/**
+ * This command represents an unknown command.
+ */
+public class UnknownCommand extends FlashcardCommand {
+ /**
+ * Prints an error message and returns.
+ *
+ * @param scanner Scanner that allows handling user input.
+ * @param flashcardList Which flashcards to perform actions on.
+ */
+ public void execute(Scanner scanner, FlashcardList flashcardList) {
+ System.out.println("Unknown command! Please try again.");
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/exceptions/FlashcardException.java b/src/main/java/seedu/duke/flashcard/exceptions/FlashcardException.java
new file mode 100644
index 0000000000..58ad4cb36c
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/exceptions/FlashcardException.java
@@ -0,0 +1,9 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.exceptions;
+
+/**
+ * Base class for all custom exceptions related to flashcards.
+ */
+public class FlashcardException extends Exception {
+}
diff --git a/src/main/java/seedu/duke/flashcard/exceptions/InvalidFlashcardIdException.java b/src/main/java/seedu/duke/flashcard/exceptions/InvalidFlashcardIdException.java
new file mode 100644
index 0000000000..da729d3ba4
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/exceptions/InvalidFlashcardIdException.java
@@ -0,0 +1,11 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.exceptions;
+
+/**
+ * Exception for when a flashcardId is not valid (i.e. no flashcard with
+ * that id appears in the list of flashcards which are currently being
+ * worked on).
+ */
+public class InvalidFlashcardIdException extends FlashcardException {
+}
diff --git a/src/main/java/seedu/duke/flashcard/exceptions/InvalidReviewModeException.java b/src/main/java/seedu/duke/flashcard/exceptions/InvalidReviewModeException.java
new file mode 100644
index 0000000000..5fc0bfafaa
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/exceptions/InvalidReviewModeException.java
@@ -0,0 +1,10 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.exceptions;
+
+/**
+ * Exception for when the input for choosing a flashcard review mode is
+ * incorrect.
+ */
+public class InvalidReviewModeException extends FlashcardException {
+}
diff --git a/src/main/java/seedu/duke/flashcard/review/RandomReviewMode.java b/src/main/java/seedu/duke/flashcard/review/RandomReviewMode.java
new file mode 100644
index 0000000000..7f3dad0a33
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/review/RandomReviewMode.java
@@ -0,0 +1,44 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.review;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+
+/**
+ * Review mode that randomly picks flashcards to review.
+ *
+ * This mode doesn't allow adjusting the difficulty of the reviewed flashcards.
+ */
+public class RandomReviewMode extends ReviewMode {
+ public RandomReviewMode(FlashcardList flashcardList) {
+ super(flashcardList);
+ }
+
+ /**
+ * Identifies the instance as a random review mode instance.
+ *
+ * @return Textual description that this is the random review mode.
+ */
+ public String getReviewModeName() {
+ return "random review mode";
+ }
+
+ /**
+ * Chooses a random flashcard to be reviewed next.
+ *
+ * @return The next flashcard to review.
+ */
+ protected Flashcard pickFlashcard() {
+ ArrayList flashcards = flashcardList.getFlashcards();
+
+ SecureRandom random = new SecureRandom();
+
+ assert random != null : "must be valid SecureRandom instance";
+
+ return flashcards.get(random.nextInt(flashcards.size()));
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/review/ReviewMode.java b/src/main/java/seedu/duke/flashcard/review/ReviewMode.java
new file mode 100644
index 0000000000..9a7f57b589
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/review/ReviewMode.java
@@ -0,0 +1,157 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.review;
+
+import seedu.duke.calendar.Calendar;
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Base class for implementing different kinds of flashcard reviews.
+ *
+ * Provides functionalities to easily review flashcards that can be used by
+ * subclasses as building blocks to implement specific kinds (e.g. random or
+ * difficulty-based) reviews.
+ */
+public abstract class ReviewMode {
+ protected FlashcardList flashcardList;
+
+ public ReviewMode(FlashcardList flashcardList) {
+ assert flashcardList != null : "flashcardList cannot be null";
+ this.flashcardList = flashcardList;
+ }
+
+ /**
+ * Abstract method to allow subclasses to identify themselves easily.
+ *
+ * @return Textual description of what kind of review mode this class is.
+ */
+ public abstract String getReviewModeName();
+
+
+ /**
+ * Starts and executes a flashcard review session.
+ *
+ * @param scanner For getting input from user.
+ */
+ public void startReviewSession(Scanner scanner, Calendar calendar) {
+ assert scanner != null : "must be a valid Scanner instance";
+
+ System.out.println(" You have started a review session in "
+ + getReviewModeName() + System.lineSeparator());
+
+ if (flashcardList.isEmpty()) {
+ System.out.println(" You have no flashcards to review!");
+ System.out.println(" Add some flashcards and try again.");
+ return;
+ }
+
+ while (true) {
+ Flashcard flashcardToReview = pickFlashcard();
+
+ printFlashcardFrontTextPrompt(flashcardToReview);
+
+ String input = scanner.nextLine();
+ input = input.toLowerCase();
+ boolean shouldTerminate = input.strip().equals("quit")
+ || input.strip().equals("q");
+ if (shouldTerminate) {
+ break;
+ }
+
+ System.out.println(" The actual back text is: "
+ + flashcardToReview.getBackText());
+ System.out.println();
+
+ if (getReviewModeName().equals("spaced repetition mode")) {
+ letUserRateReviewDifficulty(scanner, flashcardToReview);
+ }
+
+ calendar.incrementFlashcardCount();
+ }
+
+ System.out.println(" Success! You have ended this review session.");
+ }
+
+ /**
+ * Allows subclasses to choose which flashcard to review next.
+ *
+ * @return The next flashcard to review.
+ */
+ protected abstract Flashcard pickFlashcard();
+
+ /**
+ * Prints front of a flashcard and prompts the user to think of its back.
+ *
+ * @param flashcardToReview The flashcard currently being reviewed.
+ */
+ protected void printFlashcardFrontTextPrompt(Flashcard flashcardToReview) {
+ assert flashcardToReview != null : "must be valid Flashcard instance";
+
+ System.out.println(" " + "-".repeat(76));
+ System.out.println(" The front text is: "
+ + flashcardToReview.getFrontText());
+ System.out.println();
+
+ System.out.println(" Think of the answer (the back text) in " +
+ "your head.");
+ System.out.println(" Press ENTER when you are ready to compare " +
+ "it,");
+ System.out.println(" or enter q or quit to end this review " +
+ "session.");
+ }
+
+ /**
+ * Lets the user rate the difficulty of a flashcard and then adjusts it.
+ *
+ * Depending on the rating given by the user, the flashcard difficulty is
+ * increased, kept constant or decreased. If the user rates the flashcard
+ * as easy, difficulty is decreased by one; if the user rates it as
+ * medium hard, difficulty is kept unchanges; and if the user rates it as
+ * hard, difficulty is increased by one.
+ *
+ * @param scanner To get user input.
+ * @param flashcard The flashcard currently under review.
+ */
+ protected void letUserRateReviewDifficulty(Scanner scanner,
+ Flashcard flashcard) {
+ assert flashcard != null : "must be a valid Flashcard instance";
+ assert scanner != null : "must be a valid Scanner instance";
+
+ System.out.println(" How hard was it to remember the back page of "
+ + "this flashcard?");
+ System.out.println(" Input E if it was easy, M if it was "
+ + "moderately challenging ");
+ System.out.println(" or H if it was quite hard.");
+
+ final ArrayList choices = new ArrayList<>(Arrays.asList(
+ "e", "m", "h"));
+ String choice = scanner.nextLine();
+
+ while (!choices.contains(choice.toLowerCase())) {
+ System.out.println(" Invalid choice! Your choice must be E, M "
+ + "or H! Please try again.");
+
+ choice = scanner.nextLine();
+ }
+
+ int difficultyChange;
+ switch (choice.toLowerCase()) {
+ case "e":
+ difficultyChange = -1;
+ break;
+ case "m":
+ difficultyChange = 0;
+ break;
+ default:
+ difficultyChange = +1;
+ break;
+ }
+
+ flashcard.applyDifficultyChange(difficultyChange);
+ }
+}
diff --git a/src/main/java/seedu/duke/flashcard/review/SpacedRepetitionReviewMode.java b/src/main/java/seedu/duke/flashcard/review/SpacedRepetitionReviewMode.java
new file mode 100644
index 0000000000..6c981cf59b
--- /dev/null
+++ b/src/main/java/seedu/duke/flashcard/review/SpacedRepetitionReviewMode.java
@@ -0,0 +1,55 @@
+//@@author wendelinwemhoener
+
+package seedu.duke.flashcard.review;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+
+import java.util.ArrayList;
+
+/**
+ * Review mode that picks the flashcards with the highest difficulty.
+ *
+ * After each flashcard review, the reviewed flashcard's difficulty is
+ * adjusted based on the user input. This way, harder flashcards are shown
+ * more often and easier ones are shown less frequently to enhance learning
+ * efficiency.
+ */
+public class SpacedRepetitionReviewMode extends ReviewMode {
+ public SpacedRepetitionReviewMode(FlashcardList flashcardList) {
+ super(flashcardList);
+ }
+
+ /**
+ * Identifies the instance as a spaced repetition review mode instance.
+ *
+ * @return Textual description that this is the spaced repetition mode.
+ */
+ public String getReviewModeName() {
+ return "spaced repetition mode";
+ }
+
+ /**
+ * Chooses the flashcard with the highest difficulty to be reviewed next.
+ *
+ * @return The next flashcard to review.
+ */
+ protected Flashcard pickFlashcard() {
+ ArrayList flashcards = flashcardList.getFlashcards();
+
+ int maxDifficulty = Integer.MIN_VALUE;
+ Flashcard maxDifficultyFlashcard = null;
+
+ for (Flashcard flashcard : flashcards) {
+ if (flashcard.getDifficulty() > maxDifficulty) {
+ maxDifficulty = flashcard.getDifficulty();
+ maxDifficultyFlashcard = flashcard;
+ }
+ }
+
+ assert maxDifficultyFlashcard != null : "there should be a flashcard";
+ assert maxDifficulty != Integer.MIN_VALUE;
+
+ return maxDifficultyFlashcard;
+ }
+}
diff --git a/src/main/java/seedu/duke/storage/EventDirectory.java b/src/main/java/seedu/duke/storage/EventDirectory.java
new file mode 100644
index 0000000000..4eec883caf
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/EventDirectory.java
@@ -0,0 +1,95 @@
+package seedu.duke.storage;
+
+import java.io.File;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * directory for directory
+ * can list-up txt files in text folder
+ * In version 1, using only event.txt
+ * In version 2, can select or create
+ */
+
+public class EventDirectory {
+ private static Logger logger; // for logging
+ String path;
+ File file;
+
+ public EventDirectory(){
+ logger = Logger.getLogger("flashDir");
+ logger.setLevel(Level.WARNING);
+
+ String dataPath = "./data";
+
+ File dataFolder = new File(dataPath);
+ if(!dataFolder.exists()){
+ if(dataFolder.mkdir()){
+ logger.log(Level.INFO, "Created data directory");
+ //System.out.println(" Created events directory");
+ } else{
+ logger.log(Level.INFO, "Failed to create data directory");
+ //System.out.println(" Failed to create directory");
+ }
+ } else{
+ logger.log(Level.INFO, "Using data directory");
+ //System.out.println(" Using data/events directory");
+ }
+
+ path = "./data/events";
+
+ file = new File(path);
+ if(!file.exists()){
+ if(file.mkdir()){
+ logger.log(Level.INFO, "Created events directory");
+ //System.out.println(" Created events directory");
+ } else{
+ logger.log(Level.INFO, "Failed to create directory");
+ //System.out.println(" Failed to create directory");
+ }
+ } else{
+ logger.log(Level.INFO, "Using data/events directory");
+ //System.out.println(" Using data/events directory");
+ }
+ }
+
+ /**
+ * list-up saved files
+ * selecting file is for version 2
+ */
+ public void listEventFiles(){
+ String[] eventFiles = file.list();
+ if(eventFiles == null){
+ logger.log(Level.INFO, "Failed to find files");
+ //System.out.println("Failed to find files");
+ } else if(eventFiles.length == 0){
+ logger.log(Level.INFO, "No files exist");
+ //System.out.println("No files exist");
+ } else{
+ for(String eventFile : eventFiles){
+ logger.log(Level.INFO, eventFile);
+ //System.out.println(" "+eventFile);
+ }
+ }
+ }
+
+ /**
+ * return default directory
+ * for version 1
+ * @return directory for flashcard txt file
+ */
+ public String defaultDirectory() {
+ return this.path + "/event.txt";
+ }
+
+ /**
+ * return directory of flashcard txt file
+ * for version 2
+ * @param path is used for storing file path
+ * @return is used to get the path to the file
+ */
+ public String eventDirectory(String path) {
+ return this.path + path;
+ }
+
+}
diff --git a/src/main/java/seedu/duke/storage/EventStorage.java b/src/main/java/seedu/duke/storage/EventStorage.java
new file mode 100644
index 0000000000..951830b178
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/EventStorage.java
@@ -0,0 +1,103 @@
+package seedu.duke.storage;
+
+import seedu.duke.calendar.Event;
+import seedu.duke.calendar.EventList;
+import seedu.duke.calendar.Goal;
+import seedu.duke.storage.exceptions.EventFileFormatException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static seedu.duke.storage.EventStorageParser.eventFileChecker;
+
+
+/**
+ * storage for Events
+ * One storage manages one file
+ */
+public class EventStorage {
+ private static Logger logger; // for logging
+ protected String path;
+
+ public EventStorage(String path){
+ this.path = path;
+ logger = Logger.getLogger("event");
+ logger.setLevel(Level.WARNING);
+ }
+
+
+ public boolean isStorageAvailable(){
+ File f = new File(this.path);
+ return f.exists();
+ }
+
+ /**
+ * load list of events
+ * from this.path
+ * @return list of Events
+ * @throws FileNotFoundException is used if the file is not in the path
+ */
+ public EventList loadEvents() throws FileNotFoundException{
+ EventList eventList = new EventList(new ArrayList<>());
+ File f = new File (this.path);
+ Scanner s = new Scanner(f);
+
+ try{
+ while(s.hasNext()){
+ String[] eventTokens = s.nextLine().split(" \\| ");
+ eventFileChecker(eventTokens);
+ eventList.addEvent(EventStorageParser.loadEvent(eventTokens));
+ }
+ } catch (EventFileFormatException e) {
+ System.out.println("The flashcard save file is corrupted");
+ System.out.println("Automatically making new file");
+ eventList = new EventList(new ArrayList<>());
+ saveEvents(eventList.getEvents());
+ }
+
+
+ logger.log(Level.INFO, String.format(
+ " There are currently %d events in the save file",
+ eventList.getSize()));
+
+ return eventList;
+
+ }
+
+ /**
+ * saveEvents method
+ * save all events to file
+ * @param eventList is used to access the list
+ */
+ public void saveEvents(ArrayList eventList) {
+
+ try {
+ FileWriter fw = new FileWriter(path);
+
+ for (Event event : eventList) {
+ if (event.getClass() == Goal.class) {
+ fw.write(String.format("%s | %s | %s | %s \r\n",
+ event.getName(), event.getTo(), ((Goal) event).getGoal(), ((Goal) event).getCompleted()));
+ } else {
+ fw.write(String.format("%s | %s | %s \r\n",
+ event.getName(), event.getFrom(), event.getTo()));
+ }
+ }
+ fw.close();
+ } catch (IOException e){
+ //System.out.println("Failed to save.");
+ logger.log(Level.WARNING, "problem: failed to save");
+ }
+ }
+
+
+
+
+
+}
diff --git a/src/main/java/seedu/duke/storage/EventStorageParser.java b/src/main/java/seedu/duke/storage/EventStorageParser.java
new file mode 100644
index 0000000000..4fb7bafa1b
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/EventStorageParser.java
@@ -0,0 +1,75 @@
+package seedu.duke.storage;
+
+import seedu.duke.calendar.Event;
+import seedu.duke.calendar.Goal;
+import seedu.duke.storage.exceptions.EventFileFormatException;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class EventStorageParser {
+
+ private static Logger logger; // for logging
+
+ /**
+ * check the saved file format
+ * token length should be 3 or 4
+ * if token length is 3, format should be string, localdatetime, localdatetime
+ * if token length is 4, format should be string, localdatetime, int, int
+ * @param tokens is a split txt line
+ * @throws EventFileFormatException
+ */
+ public static void eventFileChecker(String[] tokens) throws EventFileFormatException {
+ if(tokens.length != 3 && tokens.length != 4) {
+ throw new EventFileFormatException();
+ }
+
+ try {
+ LocalDateTime.parse(tokens[1].trim());
+ if(tokens.length == 3){
+ LocalDateTime.parse(tokens[2].trim());
+ }
+ if(tokens.length == 4){
+ Integer.parseInt(tokens[2].trim());
+ Integer.parseInt(tokens[3].trim());
+ }
+ } catch (DateTimeParseException | NumberFormatException e) {
+ throw new EventFileFormatException();
+ }
+ }
+
+
+ /**
+ * load an event from certain format
+ * Tokens includes attributes of Event
+ * @param tokens is used to get event name
+ * @return Event object
+ */
+ public static Event loadEvent(String[] tokens){
+
+ logger = Logger.getLogger("event");
+ logger.setLevel(Level.WARNING);
+
+ assert tokens.length == 3 || tokens.length == 4: "Token length should be 3 or 4";
+
+ if(tokens.length == 3) {
+ String name = tokens[0].trim();
+ LocalDateTime from = LocalDateTime.parse(tokens[1].trim());
+ LocalDateTime to = LocalDateTime.parse(tokens[2].trim());
+
+ logger.log(Level.INFO, "loaded event");
+
+ return new Event(name, from, to);
+ }
+ String name = tokens[0].trim();
+ LocalDateTime by = LocalDateTime.parse(tokens[1].trim());
+ int goal = Integer.parseInt(tokens[2].trim());
+ int completed = Integer.parseInt(tokens[3].trim());
+
+ logger.log(Level.INFO, "loaded event");
+
+ return new Goal(name, by, goal, completed);
+ }
+}
diff --git a/src/main/java/seedu/duke/storage/FlashcardDirectory.java b/src/main/java/seedu/duke/storage/FlashcardDirectory.java
new file mode 100644
index 0000000000..466760a495
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/FlashcardDirectory.java
@@ -0,0 +1,96 @@
+package seedu.duke.storage;
+
+import java.io.File;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * directory for flashcards
+ * can list-up txt files in text folder
+ * In version 1, using only flashcard.txt
+ * In version 2, can select or create
+ */
+
+public class FlashcardDirectory {
+ private static Logger logger; // for logging
+ String path;
+ File file;
+
+ public FlashcardDirectory(){
+
+ logger = Logger.getLogger("flashDir");
+ logger.setLevel(Level.WARNING);
+
+ path = "./data/flashcards";
+
+ String dataPath = "./data";
+
+ File dataFolder = new File(dataPath);
+ if(!dataFolder.exists()){
+ if(dataFolder.mkdir()){
+ logger.log(Level.INFO, "Created data directory");
+ //System.out.println(" Created events directory");
+ } else{
+ logger.log(Level.INFO, "Failed to create data directory");
+ //System.out.println(" Failed to create directory");
+ }
+ } else{
+ logger.log(Level.INFO, "Using data directory");
+ //System.out.println(" Using data/events directory");
+ }
+
+ file = new File(path);
+ if(!file.exists()){
+ if(file.mkdir()){
+ logger.log(Level.INFO, "Created flashcards directory");
+ //System.out.println(" Created flashcards directory");
+ } else{
+ logger.log(Level.INFO, "Failed to create directory");
+ //System.out.println(" Failed to create directory");
+ }
+ } else{
+ logger.log(Level.INFO, "Using data/flashcards directory");
+ //System.out.println(" Using data/flashcards directory");
+ }
+ }
+
+ /**
+ * list-up saved files
+ * selecting file is for version 2
+ */
+ public void listFlashcardFiles(){
+ String[] flashcardFiles = file.list();
+ if(flashcardFiles == null){
+ logger.log(Level.INFO, "Failed to find files");
+ //System.out.println("Failed to find files");
+ } else if(flashcardFiles.length == 0){
+ logger.log(Level.INFO, "No files exist");
+ //System.out.println("No files exist");
+ } else{
+ for(String flashcardFile : flashcardFiles){
+ logger.log(Level.INFO, flashcardFile);
+ //System.out.println(" "+flashcardFile);
+ }
+ }
+ }
+
+ /**
+ * return default directory
+ * for version 1
+ * @return directory for flashcard txt file
+ */
+ public String defaultDirectory() {
+ return this.path + "/flashcard.txt";
+ }
+
+ /**
+ * return directory of flashcard txt file
+ * for version 2
+ * @param path
+ * @return
+ */
+ public String flashcardDirectory(String path) {
+ return this.path + path;
+ }
+
+}
diff --git a/src/main/java/seedu/duke/storage/FlashcardStorage.java b/src/main/java/seedu/duke/storage/FlashcardStorage.java
new file mode 100644
index 0000000000..5500e51d8e
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/FlashcardStorage.java
@@ -0,0 +1,114 @@
+package seedu.duke.storage;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.flashcard.FlashcardList;
+import seedu.duke.storage.exceptions.FlashcardFileFormatException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static seedu.duke.storage.FlashcardStorageParser.flashcardFileChecker;
+
+/**
+ * storage for flashcards
+ * One storage manages one file
+ */
+public class FlashcardStorage {
+ // simply implemented for save & load first
+
+ private static Logger flashlogger; // for logging
+ protected String path;
+
+ FlashcardStorageParser parser;
+
+ public FlashcardStorage(String path){
+ this.path = path;
+ flashlogger = Logger.getLogger("flash");
+ flashlogger.setLevel(Level.WARNING);
+ }
+
+
+ public boolean isStorageAvailable(){
+ File f = new File(this.path);
+ return f.exists();
+ }
+
+ /**
+ * load list of flashcards
+ * from this.path
+ * @return list of Flashcards
+ * @throws FileNotFoundException
+ */
+ public FlashcardList loadFlashcards() throws FileNotFoundException{
+
+ flashlogger.log(Level.INFO, "loading flashcard");
+
+ FlashcardList flashcardList = new FlashcardList(new ArrayList<>());
+ File f = new File (this.path);
+ Scanner s = new Scanner(f);
+
+ try{
+ while(s.hasNext()){
+ String[] flashTokens = s.nextLine().split(" \\| ");
+ flashcardFileChecker(flashTokens);
+ flashcardList.add(FlashcardStorageParser.loadFlashcard(flashTokens));
+ flashlogger.log(Level.INFO, "added flashcard");
+
+ }
+ } catch (FlashcardFileFormatException e) {
+ System.out.println("The flashcard save file is corrupted");
+ System.out.println("Automatically making new file");
+ flashcardList = new FlashcardList(new ArrayList<>());
+ saveFlashcards(flashcardList.getFlashcards());
+ }
+
+ flashlogger.log(Level.INFO, String.format(
+ "There are currently %d flashcards in the savefile",
+ flashcardList.getSize()));
+
+ return flashcardList;
+
+ }
+
+ /**
+ * saveFlashcards method
+ * save all flashcard data to file
+ * @param flashcardList
+ */
+ public boolean saveFlashcards(ArrayList flashcardList) {
+
+ try {
+ FileWriter fw = new FileWriter(path);
+
+ for (int i = 0; i < flashcardList.size(); i++) {
+
+ // get info from a flashcard
+ Flashcard flashcard = flashcardList.get(i);
+
+ int id = flashcard.getId();
+ String frontText = flashcard.getFrontText();
+ String backText = flashcard.getBackText();
+ int difficulty = flashcard.getDifficulty();
+
+ fw.write(String.format("%d | %s | %s | %d \r\n",
+ id, frontText, backText, difficulty));
+ }
+ fw.close();
+ return true;
+ } catch (IOException e){
+ flashlogger.log(Level.WARNING, "problem: failed to save");
+ return false;
+ }
+ }
+
+
+
+
+
+}
diff --git a/src/main/java/seedu/duke/storage/FlashcardStorageParser.java b/src/main/java/seedu/duke/storage/FlashcardStorageParser.java
new file mode 100644
index 0000000000..795be643e7
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/FlashcardStorageParser.java
@@ -0,0 +1,67 @@
+package seedu.duke.storage;
+
+import seedu.duke.flashcard.Flashcard;
+import seedu.duke.storage.exceptions.FlashcardFileFormatException;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * FlashcardStorageParser class
+ * Utility class for parsing
+ */
+public final class FlashcardStorageParser {
+
+ private static Logger flashlogger; // for logging
+
+ /**
+ * check the saved file format
+ * token length should be 4
+ * type should be integer, string, string, integer
+ * @param tokens is a split txt line
+ * @throws FlashcardFileFormatException
+ */
+ public static void flashcardFileChecker(String[] tokens) throws FlashcardFileFormatException {
+ if(tokens.length != 4) {
+ throw new FlashcardFileFormatException();
+ }
+
+ try {
+ Integer.parseInt(tokens[0].trim());
+ Integer.parseInt(tokens[3].trim());
+ } catch (NumberFormatException e) {
+ throw new FlashcardFileFormatException();
+ }
+ }
+
+ /**
+ * load a flash card from certain format
+ * Tokens includes attributes of Flashcard
+ * @param tokens
+ * @return Flashcard object
+ */
+ public static Flashcard loadFlashcard(String[] tokens){
+
+ flashlogger = Logger.getLogger("flash");
+ flashlogger.setLevel(Level.WARNING);
+
+ assert tokens.length == 4 : "Token length should be 4";
+
+ flashlogger.log(Level.INFO, "token length is", tokens.length);
+
+ int id = Integer.parseInt(tokens[0].trim());
+ String frontText = tokens[1].trim();
+ String backText = tokens[2].trim();
+ int difficulty = Integer.parseInt(tokens[3].trim());
+
+
+ Flashcard flashcard = new Flashcard(frontText, backText);
+
+ flashcard.setId(id);
+ flashcard.setDifficulty(difficulty);
+
+ flashlogger.log(Level.INFO, "loaded flashcard");
+
+ return flashcard;
+ }
+}
diff --git a/src/main/java/seedu/duke/storage/exceptions/EventFileFormatException.java b/src/main/java/seedu/duke/storage/exceptions/EventFileFormatException.java
new file mode 100644
index 0000000000..2d72e93e50
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/exceptions/EventFileFormatException.java
@@ -0,0 +1,8 @@
+package seedu.duke.storage.exceptions;
+
+/**
+ * Exception class for Event file format
+ * raised if file format is wrong (eg. file corrupted)
+ */
+public class EventFileFormatException extends Exception{
+}
diff --git a/src/main/java/seedu/duke/storage/exceptions/FlashcardFileFormatException.java b/src/main/java/seedu/duke/storage/exceptions/FlashcardFileFormatException.java
new file mode 100644
index 0000000000..46da6d1af1
--- /dev/null
+++ b/src/main/java/seedu/duke/storage/exceptions/FlashcardFileFormatException.java
@@ -0,0 +1,8 @@
+package seedu.duke.storage.exceptions;
+
+/**
+ * Exception class for Event file format
+ * raised if file format is wrong (eg. file corrupted)
+ */
+public class FlashcardFileFormatException extends Exception{
+}
diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java
index 2dda5fd651..2567981a3d 100644
--- a/src/test/java/seedu/duke/DukeTest.java
+++ b/src/test/java/seedu/duke/DukeTest.java
@@ -1,12 +1,137 @@
package seedu.duke;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;
+import seedu.duke.calendar.Calendar;
+import seedu.duke.calendar.CalendarManager;
+import seedu.duke.flashcard.exceptions.FlashcardException;
+import seedu.duke.flashcard.exceptions.InvalidFlashcardIdException;
+import seedu.duke.flashcard.exceptions.InvalidReviewModeException;
+import seedu.duke.flashcard.review.RandomReviewMode;
+import seedu.duke.flashcard.review.ReviewMode;
+import seedu.duke.flashcard.review.SpacedRepetitionReviewMode;
+import seedu.duke.storage.EventStorage;
+import seedu.duke.flashcard.FlashcardComponent;
+import seedu.duke.flashcard.FlashcardList;
+import seedu.duke.storage.FlashcardStorage;
+import seedu.duke.flashcard.FlashcardUi;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Scanner;
class DukeTest {
@Test
- public void sampleTest() {
+ public void testFlashcardComponent_isResponsible_notResponsible() {
+ FlashcardComponent flashcardComponent = new FlashcardComponent(new Calendar());
+
+ assertFalse(flashcardComponent.isResponsible("dfdfdfdfdf"));
+ assertFalse(flashcardComponent.isResponsible("help me"));
+ assertFalse(flashcardComponent.isResponsible(" "));
+ }
+
+ @Test
+ public void testFlashcardComponent_isResponsible_responsible() {
+ FlashcardComponent flashcardComponent = new FlashcardComponent(
+ new Calendar());
+
+ assertTrue(flashcardComponent.isResponsible("create flashcard"));
+ assertTrue(flashcardComponent.isResponsible("delete flashcard b"));
+ assertTrue(flashcardComponent.isResponsible("list flashcards"));
+ assertTrue(flashcardComponent.isResponsible("delete all flashcards"));
+ assertTrue(flashcardComponent.isResponsible("review flashcards"));
+ assertTrue(flashcardComponent.isResponsible("review flashcards c"));
+ }
+
+ @Test
+ public void testReviewMode_getReviewModeName_randomReviewMode() {
+ FlashcardList fl = new FlashcardList(new ArrayList<>());
+ ReviewMode rm = new RandomReviewMode(fl);
+
+ assertEquals(rm.getReviewModeName(), "random review mode");
+ }
+
+ @Test
+ public void testFlashcardException_initializeException() {
+ InvalidFlashcardIdException e1 = new InvalidFlashcardIdException();
+ InvalidReviewModeException e2 = new InvalidReviewModeException();
+
+ assertTrue(e1 instanceof FlashcardException);
+ assertTrue(e2 instanceof FlashcardException);
+ assertTrue(e1 instanceof Exception);
+ }
+
+ @Test
+ public void testReviewMode_getReviewModeName_spacedRepetitionReviewMode() {
+ FlashcardList fl = new FlashcardList(new ArrayList<>());
+ ReviewMode rm = new SpacedRepetitionReviewMode(fl);
+
+ assertEquals(rm.getReviewModeName(), "spaced repetition mode");
+ }
+
+ @Test
+ public void testFlashcardStorage_isAvailable(){
+ FlashcardComponent flashcardComponent = new FlashcardComponent(new Calendar());
+ FlashcardStorage storage = flashcardComponent.getStorage();
+ assertTrue(storage.isStorageAvailable());
+ }
+
+ @Test
+ public void testEventStorage_isAvailable(){
+ CalendarManager calendarManager = new CalendarManager(new Calendar(), new ArrayList<>());
+ EventStorage storage = calendarManager.getStorage();
+ assertTrue(storage.isStorageAvailable());
+ }
+
+ @Test
+ public void testFlashcardStorage_isSavingCorrectly(){
+ String input = "create flashcard\n";
+ input += "Hello\n";
+ input += "Duke\n";
+ InputStream in = new ByteArrayInputStream(input.getBytes());
+ System.setIn(in);
+
+ Scanner scanner = new Scanner(System.in);
+
+ FlashcardComponent flashcardComponent = new FlashcardComponent(new Calendar());
+ FlashcardStorage storage = flashcardComponent.getStorage();
+
+ FlashcardUi ui = flashcardComponent.getUi();
+ ui.setScanner(scanner);
+
+ flashcardComponent.processInput(scanner.nextLine());
+
+ FlashcardList flashcardList = flashcardComponent.getFlashcardList();
+
+ assertTrue(storage.saveFlashcards(flashcardList.getFlashcards()));
+ }
+
+
+ @Test
+ public void sampleTestCalendar() {
assertTrue(true);
}
+
+ @Test
+ public void testCalendar_isResponsible_true() {
+ CalendarManager calendarManager = new CalendarManager(new Calendar(), new ArrayList<>());
+
+ assertTrue(calendarManager.isResponsible("add event"));
+ assertTrue(calendarManager.isResponsible("list events "));
+ assertTrue(calendarManager.isResponsible("delete event"));
+ }
+
+ @Test
+ public void testCalendar_isResponsible_false() {
+ CalendarManager calendarManager = new CalendarManager(new Calendar(), new ArrayList<>());
+
+ assertFalse(calendarManager.isResponsible("add"));
+ assertFalse(calendarManager.isResponsible("hello"));
+ assertFalse(calendarManager.isResponsible("event"));
+ }
}
diff --git a/text-ui-test/ACTUAL.TXT b/text-ui-test/ACTUAL.TXT
new file mode 100644
index 0000000000..e627e190dd
--- /dev/null
+++ b/text-ui-test/ACTUAL.TXT
@@ -0,0 +1,2 @@
+Enter your command: Invalid command! Please try again.
+Enter your command:
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED-UNIX.TXT b/text-ui-test/EXPECTED-UNIX.TXT
new file mode 100644
index 0000000000..e627e190dd
--- /dev/null
+++ b/text-ui-test/EXPECTED-UNIX.TXT
@@ -0,0 +1,2 @@
+Enter your command: Invalid command! Please try again.
+Enter your command:
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..e627e190dd 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +1,2 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
+Enter your command: Invalid command! Please try again.
+Enter your command:
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..28a42c47fc 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +1 @@
-James Gosling
\ No newline at end of file
+calendar
\ No newline at end of file