+
+## Introduction
+Welcome to Study It Developer Guide!
+
+This document details the architecture of Study It. It aims to provide an overview of the high-level system
+architecture and design of the app. It will also break down the design of the app into smaller components and be
+explained in detail. This will allow the readers to understand the architecture and design flow of Study It and
+how it operates.
+
+Study It is an interactive desktop app that helps NUS students manage their study related matters especially during
+this online study environment. It is optimized for use via a Command Line Interface (CLI). It can keep track of the
+student’s various study matters, present them in an organized and thoughtful manner to help them organize their
+study life. It will also provide various functionalities to help with their studies.
+
+The 4 main functionalities available now are bookmark, timetable, academic tracker and flashcard.
+Each of this will be discussed in detail under the “Design & Implementation” section later in the document.
+
+## About
+
+The target audience for this document are other developers who want to understand the system architecture and design of Study It. The following groups might be the particular intended audience of this developer guide:
+
+* Study It developers - to understand the entire system architecture and follow the design to build increments to the system
+* CS2113 lecturer/teaching assistants - to evaluate the system architecture and design of Study It
+* CS2113 peers - to understand the architecture and provide feedback
+
+The following are the common notations and symbols used in this document:
+
+* `bolded text` - Class name, folder name in the source code
+* [hyperlinks]() - Redirects you to different part of the document or open the relevant website
+
+
+
+
+
+## Setting up & getting started
+**Requirements**
+* Java 11.0.8
+ * You may refer to this [website](https://www.oracle.com/java/technologies/javase/jdk11-archive-downloads.html)
+to download and install Java 11.0.8
+ * The installation guide can be found in the following websites:
+ * [Windows](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-microsoft-windows-platforms.html#GUID-A7E27B90-A28D-4237-9383-A58B416071CA)
+ * [Linux](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-linux-platforms.html)
+ * [Mac](https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm#JSJIG-GUID-2FE451B0-9572-4E38-A1A5-568B77B146DE)
+
+**Running the software**
+1. Download the tP.jar file from our [Github release](https://github.com/AY2021S1-CS2113T-T12-1/tp/releases) and
+place it in an empty folder
+2. Open your computer’s command prompt
+3. Change the directory of the command prompt to the folder containing tP.jar file
+4. Type `java -jar tp.jar` into the command prompt and press Enter to execute it
+5. If the application runs successfully, you’ll be greeted by a welcome message
+
+
+
+
+
+**Setting up the project on your PC**
+
+First, **fork** this repo, and **clone** the fork into your computer.
+
+If you plan to use Intellij IDEA (highly recommended):
+1. Configure the JDK: Configuring the JDK to ensure Intellij is configured to use JDK 11.
+2. Import the project as a Gradle project.
+3. Run the studyit.StudyIt and try a few commands.
+4. Run the tests to ensure they all pass.
+
+
+
## Design & implementation
+This section explains the architecture of our software and the design of each component.
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+### Major components
+This section introduces the multiple components in Study It.
+
-## Product scope
-### Target user profile
+Study It contains 4 major functional components which are the
+bookmark, timetable, academic and flashcard. Each of these component
+provide different functionalities, and they combine to form our software -- Study It.
-{Describe the target user profile}
+Component | What it does
+----------|----------------
+Bookmark | Stores internet links under different categories for easier access
+Timetable | Tracks and display your weekly schedule
+Academic | Stores important contacts and keep track of your grades
+Flashcard | Stores study questions and allow you to quiz yourself for easier memorization
-### Value proposition
+The **main component** of Study It helps user access each of these components.
+It processes the user input, provides general functionalities to traverse the software and other
+helpful functionalities. This will be further explained under Study It's design later.
-{Describe the value proposition: what problem does it solve?}
+
-## User Stories
+### Architecture
+This section describes the overall architecture of Study It.
-|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|
+
-## Non-Functional Requirements
+The *Architecture Diagram* given above explains the high-level design of the software.
+Each component in the diagram will be briefly explained below.
-{Give non-functional requirements}
+The **`main`** in **`Study It`** is responsible for initializing all the other components
+in the software.
-## Glossary
+The following is a brief overview of the components in Study It:
+* **UI**: Handles the communication between the software and the user
+* **Parser**: Processes the input from the user
+* **Execution**: Perform the actions determined by the parser
+
+The following components processes their respective actions (parsing and execution) and handles their own
+storage component:
+* **Bookmark**
+* **Timetable**
+* **Academic**
+* **Flashcard**
+
+**General commands** are commands that takes priority in execution no matter which mode the software is currently
+in.
+
+
+
+**Modes of the program**
+
+Study It has 5 **modes** that the user can navigate between:
+* **Main menu**: Default mode when booting the software, there are no functionalities tied to this mode
+* **Bookmark**
+* **Timetable**
+* **Academic**
+* **Flashcard**
+
+Each of these modes has their own unique commands. The user must switch to that mode to perform the
+mode's functionalities.
+
+User can switch between these modes at any point when using the software.
+
+**How the architecture components interact with each other**
+
+The following sequence diagram shows the interactions within the software when command is received from the user
+
+
+
+As shown in the sequence diagram above, the user will interact with Study It via the User Interface (UI).
+The commands received will then be parsed to identify the type of command. If the command is one of the
+general commands, it'll be processed and provide output. Otherwise, the command will be relayed
+to different components to be processed based on the software's current mode.
+
+
+
+### Main Component
+
+This section will give an overview of the main component of Study It.
+
+The following class diagram shows the components related to the main Study It component and their respective
+details.
+
+
+
+The main class being run for the program is contained under `StudyIt` class.
+As there are multiple modes of our app (main menu/bookmark/timetable/academic/flashcard),
+the Mode enumeration and a private static currentMode of Mode type is introduced to monitor the current
+operating mode of StudyIt. This is to allow the program to respond to different commands under different modes.
+
+Each command input by the user will be processed by CommandParser class to determine the command type.
+This information, along with the original command string will be passed into Command class and executed under
+executeCommand(). If it is one of the general commands, it will be processed by that class.
+If it isn’t, the Command class will detect the current mode of the program and run that command string under that
+specific mode, distributed under handleNonGeneralCommand() method. If it still doesn’t parse successfully,
+it will be considered an invalid command and an error message will be printed out.
+
+The classes Ui, ErrorMessage, HelpMessage and MainMenu help handle the printing of various user interfaces of the
+program. ErrorMessage, HelpMessage and MainMenu are subclasses of Ui to make use of the methods in Ui.
+
+StudyIt class will also initialize various instances of classes such as TimeTableRun, FlashCardRun,
+ArrayList, ArrayList, ArrayList and pass it to Command class to perform
+each mode’s functionality.
+
+
+
+### Bookmark Component
+
+This bookmark section consists of how the bookmark feature is implemented.
+The bookmark feature is implemented similarly to the main architecture, however,
+in a smaller scale and a more bookmark-specific way. The figure below illustrates the general overview,
+the associations and the multiplicity of the bookmark classes.
+
+
+
+**API:** `BookmarkRun`.
+
+The bookmark component consists of six major classes: `BookmarkRun`, `BookmarkStorage`, `BookmarkUi`,
+`BookmarkCategory`, `BookmarkList` and `BookmarkParser`.
+As shown in the figure above, `BookmarkRun` is
+* The main class to be called when the bookmark mode is accessed.
+* The main class to access other bookmark classes.
+
+The figure given below is the sequence diagram of how the classes interact with each
+other when bookmark mode is accessed from the main function.
+
+
+
+The bookmark component has two modes: the main bookmark mode and the category mode.
+As shown in the figure above, when `BookmarkRun` is called,
+`BookmarkParser` will be called and return a `BookmarkCommand`.
+Afterwards, `BookmarkRun` will then call `executeCommand` in `BookmarkCommand` which executes
+the intended actions. Then, it will call `getCategorymode` to get the current mode the user is in.
+
+**Bookmark Implementation**
+
+A more detailed explanation of `BookmarkCommand`, `BookmarkCategory` and `BookmarkList` will be
+shown below. `BookmarkUi` and `BookmarkStorage` follow the same design implementations as the main
+architecture. The below figure shows the command classes available and they are called based on the
+`BookmarkParser` class as illustrated in the figure above.
+
+
+
+The figure below shows a more detailed sequence diagram of how the `BookmarkCategory`, `BookmarkCommand`
+and `BookmarkList` interacts with each other for the scenario when the user input an `AddLinkCommand`
+in Bookmark mode.
+
+
+
+
-* *glossary item* - Definition
+### Timetable Component
-## Instructions for manual testing
+This section will describe in detail how some features inside the timetable section have been
+implemented.
+
+
+
+**API:** `TimeTableRun`.
+
+The timetable component consists of 7 major classes as shown. The above figure illustrates the
+ association and the multiplicity of the classes.
+
+ 1. As shown in the figure, `TimetableRun` is the main class to be accessed
+ when the timetable function is called.
+ 1. It associates with the `TimeTableStorage` class which is used to save data into a text file
+ 1. `DateList` class that contains a number of `EventList`.
+ 1. `EventList` contains a number of `Event`.
+ 1. `Event` class is the abstract parent class for `Lesson` and `Activity`.
+ 1. `Event` class also contains a number of `Duration` and it has a dependency on the `EvenType` enum.
+
+
+
+**Timetable Implementation**
+
+This section explains the details on how certain features are implemented in Timetable.
+
+The figure below is the sequence diagram of the major interactions between classes when
+the main function makes the run(command) API call and the command is "add class",
+"show schedule", "show link", or "delete class" .
+
+
+
+When command="add class" the `run(command)` method calls the `commandParse()` method from the `TimeTableParser` which the function
+will call `addClass()` function from the `TimeTableCommand` Class. New `Lesson` Class will be initialised based on user input.
+Following that a `addClassPeriod()` function will be called taking in the new lesson class initialised to add all the time slots
+into lesson class. This class will then be returned to `TimetableParser` class where it will call the `addEvent()` method in DateList
+to add the new `Lesson` Class into the arrayList within `DateList` Class. `WriteFile()` method in `Storage` will also be called to
+save the infomation of the new `Lesson` class to the data file.
+
+Other possible commands that are not shown in the diagram will interact between classes in a similar way,
+where command will be passed to the TimeTableParser Class where it interprets the command and calls the respective
+function from the TimeTableCommand Class.
+
+
+
+### Academic Component
+
+This section will describe in detail how some features inside the academic tracker section have been implemented.
+The following diagram illustrates the general overview, the associations and the multiplicity of the academic classes.
+
+
+
+API: `java.academic`
+
+The above diagram looks at the overall structure of how the academic tracker is being implemented.
+This component is split into 7 different classes,
+their associations and multiplicity as explained in the above diagram.
+The functions of the academic tracker will be called through the `AcademicRun` class
+when the program is in academic mode, which will subsequently call
+the functions in `PersonBook` or `GradeBook`.
+
+
+The academic component:
+* initialises two arraylists, `ArrayList` and `ArrayList`
+to store the relevant `Grade` and `People` objects.
+* uses `AcademicCommandParser` to parse the user command.
+* identifies `AcademicCommandType` to decide
+which of the commands under `PersonBook` or `GradeBook` is to be executed.
+* calls `AcademicStorage` to store the current set of data into the local storage file.
+
+
+
+**Academic Implementation**
+
+This section explains the details on how certain features
+are implemented in the academic tracker.
+
+**GradeBook Features**
+
+The grade features are facilitated by `Gradebook`, which further make use of `Grade`.
+Each `Grade` will contain information such as the module's title, credits, grade, status of SU and status of star.
+All grades are stored internally under `AcademicRun` as an array list `ArrayList`.
+
+It implements the following important operations:
+* `addGrade(String[], ArrayList)`:Adds a `Grade` to the `ArrayList`.
+* `printCap(ArrayList)`:Calculate the current CAP based on the `ArrayList`.
+* `printListOfGrades(ArrayList)`:Print out all the `Grade` that are currently stored inside `ArrayList`.
+* `deleteGrade(Integer, ArrayList)`:Delete a `Grade` from a specified index inside `ArrayList`.
+* `suGradeInGradeBook(Integer, ArrayList)`:Su a `Grade` from a specified index inside `ArrayList`.
+* `starGrade(Integer, ArrayList)`:Star a `Grade` from a specified index inside `ArrayList`.
+
+The following diagram demonstrates an example of how the Su Grade function works:
+
+
+
+
+
+With reference to above diagram, it can be observed that whenever a command modifies the array lists,
+`AcademicStorage` is called to update the local storage files.
+
+**PersonBook Features**
+
+The contact features are facilitated by `Personbook`, which further make use of `Person`.
+In terms of general structure, it is largely similar to that of `GradeBook`'s.
+
+
+
+
+### Flashcard Component
+
+This section will describe in detail how the flashcard feature is implemented.
+
+
+
+
+The above diagram looks at the overall structure of how the flashcard component is being implemented.
+This component is split into 4 different classes, their associations and multiplicity as explained in
+the above Figure.
+1. The main class `FlashcardRun` will be accessed when the flashcard mode is called in `StudyIt` Class.
+1. `FlashcardRun` class is associated with `FlashcardStorage` class that is used to store data in .txt file.
+1. `FlashcardDeck` class which contains any number of `Flashcards`.
+
+**Flashcard Implementation**
+
+This section explains the details on how certain features are implemented in flashcard.
+
+When `FlashcardRun` is first initialised by `StudyIt`, it will construct
+the `FlashcardDeck` class.
+
+
+
+With reference to the figure above, as an "add card" command is given by the user, `FlashcardRun` will take in the
+command and call `addCard()` method in `FlashcardDeck` which constructs a new Flashcard object and stores
+it inside the `FlashcardDeck` object. The `addCard()` function will then show the user the question and
+answer of the flashcard that has been created.
+
+Other possible commands that are not shown in the figure work in a similar way where command is parsed in `FlashcardRun` Class,
+and calls the corresponding function within the `FlashcardDeck` Class. `WriteToFile` function is called at the end of the
+process to update any changes to the deck to the data file.
+
+
+
+
+
+## Documentation, logging, testing, configuration, dev-ops
+### Testing guide
+Running tests:
+The main way that was used to run the test for Study It is:
+Using IntelliJ JUnit test runner.
+A. To run all tests, right-click on the src/test/java folder and choose
+Run Test in ‘tp.test’
+B. To run a subset of tests, you can right-click on a test package,
+test class or a test and choose Run ‘ABC’.
+Type of Tests
+This project has 5 types of tests. 4 tests to test each feature and 1 test to test the main integration of the whole application.
+
+### Logging guide
+We are using java.util.logging package for logging.
+The StudyItLog class is used to manage the logging levels and logging destinations.
+Log messages are output through the console and to a .log file.
+The output logging level can be controlled using .setlevel( )
+When choosing a level for a log message, follow the following conventions:
+1. SEVERE: A critical problem detected which may cause the termination of the application.
+2. WARNING: Can continue, but with caution.
+3. INFO: Information showing the noteworthy actions by the App.
+4. FINE: Details that are not usually noteworthy but may be useful in debugging.
+
+
+### DevOps Guide
+Build automation:
+This project uses Gradle for build automation management.
+./gradlew build - check for checkstyle error and runs all tests
+Code coverage
+This project uses code coverage that is in IntelliJ IDE to check for the coverage of the code.
+
+
+
+## Appendix: Requirement
+### Product scope
+**Target user profile:**
+* studies in NUS
+* has a need to manage a significant number of links
+* has a need to manage their classes in a timetable
+* has a need to manage their grades
+* has a need to manage contact numbers of professors and teaching assistants.
+* has a need to memorise content to study
+* prefer desktop apps over other types
+* can type fast
+* prefers typing to mouse interactions
+* is reasonably comfortable using CLI apps
+
+**Value proposition:**
+* manage links faster than a typical mouse/GUI driven app
+* manage grades more easily than a typical mouse/GUI driven app
+* manage contact numbers of professors and teaching assistants more effectively than a typical mouse/GUI driven app
+* manage timetable in a more organised manner than a typical mouse/GUI driven app
+* manage study content more efficiently than a typical mouse/GUI driven app
+
+#### User Stories
+
+|Version| As a ... | I want to ... | So that I ...|
+|--------|----------|---------------|------------------|
+|v1.0|Student in Nus|organise my zoom links|don’t need to find the zoom link everytime lectures/tutorials start.|
+|v1.0|student attending online classes|keep track of the timetable of my lessons whether it is online or offline|do not miss any lessons.|
+|v2.0|Student in Nus|organise all the useful signup links (internship/ hackathon/ talks) sent to our emails|can keep track of my time and dates of any relevant events.|
+|v1.0|Student in Nus|keep track of my results and the number of SUs I have left,|can plan my semester properly|
+|v1.0|student with packed timetables|see clashes in my timetable |can plan things without overlapping events.|
+|v1.0|student taking a mod that requires me to memorize a lot of contents|organize the contents into flashcards|can revise them on the go.|
+|v1.0|student who is worried about my results|calculate my CAP based on estimated grades|know i won’t get expelled :’)|
+|v1.0|Student in Nus|keep track of my profs and ta’s contacts|know who to find when i have troubles.|
+|v1.0|Student in Nus|bookmark all the important NUS websites|can access them more easily|
+
+#### Non-Functional Requirements
+
+* Should work on any [mainstream OS](#glossary) as long as it has Java 11 or above installed.
+* A user with above average typing speed for regular English text
+(i.e. not code, not system admin commands) should be able to accomplish most of the
+tasks faster using commands than using the mouse.
+
+## Glossary
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+* *Mainstream OS* - Windows, Unix, Linux, OS-X
\ No newline at end of file
diff --git a/docs/Images/AcademicUG/Academic_3_1.png b/docs/Images/AcademicUG/Academic_3_1.png
new file mode 100644
index 0000000000..4fdb775985
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_1.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_10.png b/docs/Images/AcademicUG/Academic_3_10.png
new file mode 100644
index 0000000000..ee5512027a
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_10.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_11.png b/docs/Images/AcademicUG/Academic_3_11.png
new file mode 100644
index 0000000000..26fe09cb10
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_11.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_12.png b/docs/Images/AcademicUG/Academic_3_12.png
new file mode 100644
index 0000000000..ffbdd72582
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_12.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_2.png b/docs/Images/AcademicUG/Academic_3_2.png
new file mode 100644
index 0000000000..000c48955b
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_2.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_3.png b/docs/Images/AcademicUG/Academic_3_3.png
new file mode 100644
index 0000000000..b81db02ce9
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_3.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_4.png b/docs/Images/AcademicUG/Academic_3_4.png
new file mode 100644
index 0000000000..3505e5bf30
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_4.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_5.png b/docs/Images/AcademicUG/Academic_3_5.png
new file mode 100644
index 0000000000..11b9abf843
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_5.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_6.png b/docs/Images/AcademicUG/Academic_3_6.png
new file mode 100644
index 0000000000..7b93436ca9
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_6.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_7.png b/docs/Images/AcademicUG/Academic_3_7.png
new file mode 100644
index 0000000000..75d759fe66
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_7.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_8.png b/docs/Images/AcademicUG/Academic_3_8.png
new file mode 100644
index 0000000000..0307cda95e
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_8.png differ
diff --git a/docs/Images/AcademicUG/Academic_3_9.png b/docs/Images/AcademicUG/Academic_3_9.png
new file mode 100644
index 0000000000..25341022a4
Binary files /dev/null and b/docs/Images/AcademicUG/Academic_3_9.png differ
diff --git a/docs/Images/Academic_Class_Diagram.png b/docs/Images/Academic_Class_Diagram.png
new file mode 100644
index 0000000000..b340a07676
Binary files /dev/null and b/docs/Images/Academic_Class_Diagram.png differ
diff --git a/docs/Images/Academic_Sequence_Diagram.png b/docs/Images/Academic_Sequence_Diagram.png
new file mode 100644
index 0000000000..5f191febb7
Binary files /dev/null and b/docs/Images/Academic_Sequence_Diagram.png differ
diff --git a/docs/Images/Architecture.drawio b/docs/Images/Architecture.drawio
new file mode 100644
index 0000000000..dd7d0426c3
--- /dev/null
+++ b/docs/Images/Architecture.drawio
@@ -0,0 +1 @@
+UzV2zq1wL0osyPDNT0nNUTV2VTV2LsrPL4GwciucU3NyVI0MMlNUjV1UjYwMgFjVyA2HrCFY1qAgsSg1rwSLBiADYTaQg2Y1AA==
\ No newline at end of file
diff --git a/docs/Images/ArchitectureDiagrams/architecture.png b/docs/Images/ArchitectureDiagrams/architecture.png
new file mode 100644
index 0000000000..f65fd28e47
Binary files /dev/null and b/docs/Images/ArchitectureDiagrams/architecture.png differ
diff --git a/docs/Images/ArchitectureDiagrams/components.png b/docs/Images/ArchitectureDiagrams/components.png
new file mode 100644
index 0000000000..4642e94db3
Binary files /dev/null and b/docs/Images/ArchitectureDiagrams/components.png differ
diff --git a/docs/Images/ArchitectureDiagrams/overviewsequence.png b/docs/Images/ArchitectureDiagrams/overviewsequence.png
new file mode 100644
index 0000000000..2d6e342e71
Binary files /dev/null and b/docs/Images/ArchitectureDiagrams/overviewsequence.png differ
diff --git a/docs/Images/BookmarkDG/AddCommand.png b/docs/Images/BookmarkDG/AddCommand.png
new file mode 100644
index 0000000000..e29bc43655
Binary files /dev/null and b/docs/Images/BookmarkDG/AddCommand.png differ
diff --git a/docs/Images/BookmarkDG/Bookmark Sequence Diagram.drawio b/docs/Images/BookmarkDG/Bookmark Sequence Diagram.drawio
new file mode 100644
index 0000000000..060bd18707
--- /dev/null
+++ b/docs/Images/BookmarkDG/Bookmark Sequence Diagram.drawio
@@ -0,0 +1,312 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Images/BookmarkDG/BookmarkRun_Class.png b/docs/Images/BookmarkDG/BookmarkRun_Class.png
new file mode 100644
index 0000000000..eff1b96293
Binary files /dev/null and b/docs/Images/BookmarkDG/BookmarkRun_Class.png differ
diff --git a/docs/Images/BookmarkDG/Bookmark_ClassDiagram.drawio b/docs/Images/BookmarkDG/Bookmark_ClassDiagram.drawio
new file mode 100644
index 0000000000..e318cd2f58
--- /dev/null
+++ b/docs/Images/BookmarkDG/Bookmark_ClassDiagram.drawio
@@ -0,0 +1,453 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Images/BookmarkDG/Sequence_Diagram.png b/docs/Images/BookmarkDG/Sequence_Diagram.png
new file mode 100644
index 0000000000..ea087b8013
Binary files /dev/null and b/docs/Images/BookmarkDG/Sequence_Diagram.png differ
diff --git a/docs/Images/BookmarkDG/bookmarkCommand_Class.png b/docs/Images/BookmarkDG/bookmarkCommand_Class.png
new file mode 100644
index 0000000000..e1841e7428
Binary files /dev/null and b/docs/Images/BookmarkDG/bookmarkCommand_Class.png differ
diff --git a/docs/Images/BookmarkUG/Figure1.png b/docs/Images/BookmarkUG/Figure1.png
new file mode 100644
index 0000000000..a996c8003e
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure1.png differ
diff --git a/docs/Images/BookmarkUG/Figure10.png b/docs/Images/BookmarkUG/Figure10.png
new file mode 100644
index 0000000000..3050f8f002
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure10.png differ
diff --git a/docs/Images/BookmarkUG/Figure11.png b/docs/Images/BookmarkUG/Figure11.png
new file mode 100644
index 0000000000..f9592571c8
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure11.png differ
diff --git a/docs/Images/BookmarkUG/Figure2.png b/docs/Images/BookmarkUG/Figure2.png
new file mode 100644
index 0000000000..37b2fcc4f2
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure2.png differ
diff --git a/docs/Images/BookmarkUG/Figure3.png b/docs/Images/BookmarkUG/Figure3.png
new file mode 100644
index 0000000000..423cde9c07
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure3.png differ
diff --git a/docs/Images/BookmarkUG/Figure4.png b/docs/Images/BookmarkUG/Figure4.png
new file mode 100644
index 0000000000..a239007278
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure4.png differ
diff --git a/docs/Images/BookmarkUG/Figure5.png b/docs/Images/BookmarkUG/Figure5.png
new file mode 100644
index 0000000000..c1a61ce2ca
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure5.png differ
diff --git a/docs/Images/BookmarkUG/Figure6.png b/docs/Images/BookmarkUG/Figure6.png
new file mode 100644
index 0000000000..f86e497e8e
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure6.png differ
diff --git a/docs/Images/BookmarkUG/Figure7.png b/docs/Images/BookmarkUG/Figure7.png
new file mode 100644
index 0000000000..3e821f72ab
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure7.png differ
diff --git a/docs/Images/BookmarkUG/Figure8.png b/docs/Images/BookmarkUG/Figure8.png
new file mode 100644
index 0000000000..f266ff1238
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure8.png differ
diff --git a/docs/Images/BookmarkUG/Figure9.png b/docs/Images/BookmarkUG/Figure9.png
new file mode 100644
index 0000000000..10d75e7299
Binary files /dev/null and b/docs/Images/BookmarkUG/Figure9.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_1.png b/docs/Images/FlashcardUG/Flashcard_4_1.png
new file mode 100644
index 0000000000..372a56776d
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_1.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_2.png b/docs/Images/FlashcardUG/Flashcard_4_2.png
new file mode 100644
index 0000000000..58cf5b2e95
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_2.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_2_1.png b/docs/Images/FlashcardUG/Flashcard_4_2_1.png
new file mode 100644
index 0000000000..7e0c25b548
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_2_1.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_3.png b/docs/Images/FlashcardUG/Flashcard_4_3.png
new file mode 100644
index 0000000000..13e434e06f
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_3.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_4.png b/docs/Images/FlashcardUG/Flashcard_4_4.png
new file mode 100644
index 0000000000..c43f0fc851
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_4.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_5.png b/docs/Images/FlashcardUG/Flashcard_4_5.png
new file mode 100644
index 0000000000..b6d6013bb6
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_5.png differ
diff --git a/docs/Images/FlashcardUG/Flashcard_4_6.png b/docs/Images/FlashcardUG/Flashcard_4_6.png
new file mode 100644
index 0000000000..fbaec94495
Binary files /dev/null and b/docs/Images/FlashcardUG/Flashcard_4_6.png differ
diff --git a/docs/Images/Flashcard_Class.png b/docs/Images/Flashcard_Class.png
new file mode 100644
index 0000000000..1ed5deb840
Binary files /dev/null and b/docs/Images/Flashcard_Class.png differ
diff --git a/docs/Images/GeneralUG/bookmarkhelp.png b/docs/Images/GeneralUG/bookmarkhelp.png
new file mode 100644
index 0000000000..29b2bde23d
Binary files /dev/null and b/docs/Images/GeneralUG/bookmarkhelp.png differ
diff --git a/docs/Images/GeneralUG/cdBookmark.png b/docs/Images/GeneralUG/cdBookmark.png
new file mode 100644
index 0000000000..1c489e98a3
Binary files /dev/null and b/docs/Images/GeneralUG/cdBookmark.png differ
diff --git a/docs/Images/GeneralUG/cdacademic.png b/docs/Images/GeneralUG/cdacademic.png
new file mode 100644
index 0000000000..3337251c7f
Binary files /dev/null and b/docs/Images/GeneralUG/cdacademic.png differ
diff --git a/docs/Images/GeneralUG/exit.png b/docs/Images/GeneralUG/exit.png
new file mode 100644
index 0000000000..99b06f6e03
Binary files /dev/null and b/docs/Images/GeneralUG/exit.png differ
diff --git a/docs/Images/GeneralUG/exitmode.png b/docs/Images/GeneralUG/exitmode.png
new file mode 100644
index 0000000000..385e79f2e7
Binary files /dev/null and b/docs/Images/GeneralUG/exitmode.png differ
diff --git a/docs/Images/GeneralUG/help.png b/docs/Images/GeneralUG/help.png
new file mode 100644
index 0000000000..0867cea5e9
Binary files /dev/null and b/docs/Images/GeneralUG/help.png differ
diff --git a/docs/Images/GeneralUG/highlight.png b/docs/Images/GeneralUG/highlight.png
new file mode 100644
index 0000000000..a02950d079
Binary files /dev/null and b/docs/Images/GeneralUG/highlight.png differ
diff --git a/docs/Images/GeneralUG/location_bookmark.png b/docs/Images/GeneralUG/location_bookmark.png
new file mode 100644
index 0000000000..a5f8a49c7b
Binary files /dev/null and b/docs/Images/GeneralUG/location_bookmark.png differ
diff --git a/docs/Images/GeneralUG/location_flashcard.png b/docs/Images/GeneralUG/location_flashcard.png
new file mode 100644
index 0000000000..ced77ddfa0
Binary files /dev/null and b/docs/Images/GeneralUG/location_flashcard.png differ
diff --git a/docs/Images/GeneralUG/welcomemessage.png b/docs/Images/GeneralUG/welcomemessage.png
new file mode 100644
index 0000000000..19c24e71c3
Binary files /dev/null and b/docs/Images/GeneralUG/welcomemessage.png differ
diff --git a/docs/Images/GeneralUG/wrongmodeindex.png b/docs/Images/GeneralUG/wrongmodeindex.png
new file mode 100644
index 0000000000..4db42e8991
Binary files /dev/null and b/docs/Images/GeneralUG/wrongmodeindex.png differ
diff --git a/docs/Images/MainComponentDiagrams/maincomponent.png b/docs/Images/MainComponentDiagrams/maincomponent.png
new file mode 100644
index 0000000000..a617b6e1ce
Binary files /dev/null and b/docs/Images/MainComponentDiagrams/maincomponent.png differ
diff --git a/docs/Images/TeamPhotos/luziyi.png b/docs/Images/TeamPhotos/luziyi.png
new file mode 100644
index 0000000000..87a835b6e2
Binary files /dev/null and b/docs/Images/TeamPhotos/luziyi.png differ
diff --git a/docs/Images/TeamPhotos/sihui.png b/docs/Images/TeamPhotos/sihui.png
new file mode 100644
index 0000000000..2f57063442
Binary files /dev/null and b/docs/Images/TeamPhotos/sihui.png differ
diff --git a/docs/Images/TeamPhotos/yuanbing.png b/docs/Images/TeamPhotos/yuanbing.png
new file mode 100644
index 0000000000..5a6271ae75
Binary files /dev/null and b/docs/Images/TeamPhotos/yuanbing.png differ
diff --git a/docs/Images/TeamPhotos/yuheng.png b/docs/Images/TeamPhotos/yuheng.png
new file mode 100644
index 0000000000..8073556a99
Binary files /dev/null and b/docs/Images/TeamPhotos/yuheng.png differ
diff --git a/docs/Images/TimeTable class diagram.drawio b/docs/Images/TimeTable class diagram.drawio
new file mode 100644
index 0000000000..36e6f206b3
--- /dev/null
+++ b/docs/Images/TimeTable class diagram.drawio
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Images/TimeTable class diagram.png b/docs/Images/TimeTable class diagram.png
new file mode 100644
index 0000000000..b4c24f5cba
Binary files /dev/null and b/docs/Images/TimeTable class diagram.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_1.png b/docs/Images/TimetableUG/Timetable_2_1.png
new file mode 100644
index 0000000000..512681fda5
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_1.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_10.png b/docs/Images/TimetableUG/Timetable_2_10.png
new file mode 100644
index 0000000000..6ab8c923a9
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_10.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_2.png b/docs/Images/TimetableUG/Timetable_2_2.png
new file mode 100644
index 0000000000..96bbd9fb58
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_2.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_3.png b/docs/Images/TimetableUG/Timetable_2_3.png
new file mode 100644
index 0000000000..8aa2b4a765
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_3.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_4.png b/docs/Images/TimetableUG/Timetable_2_4.png
new file mode 100644
index 0000000000..951de43727
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_4.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_5.png b/docs/Images/TimetableUG/Timetable_2_5.png
new file mode 100644
index 0000000000..60ae8ffa6b
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_5.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_6.png b/docs/Images/TimetableUG/Timetable_2_6.png
new file mode 100644
index 0000000000..307f0f2c30
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_6.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_7.png b/docs/Images/TimetableUG/Timetable_2_7.png
new file mode 100644
index 0000000000..e890ea0a14
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_7.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_8.png b/docs/Images/TimetableUG/Timetable_2_8.png
new file mode 100644
index 0000000000..bca9b6e7ce
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_8.png differ
diff --git a/docs/Images/TimetableUG/Timetable_2_9.png b/docs/Images/TimetableUG/Timetable_2_9.png
new file mode 100644
index 0000000000..ae546f73ce
Binary files /dev/null and b/docs/Images/TimetableUG/Timetable_2_9.png differ
diff --git a/docs/Images/addCard_sequenceDiagram.png b/docs/Images/addCard_sequenceDiagram.png
new file mode 100644
index 0000000000..9aa0031be2
Binary files /dev/null and b/docs/Images/addCard_sequenceDiagram.png differ
diff --git a/docs/Images/cheatsheet1.png b/docs/Images/cheatsheet1.png
new file mode 100644
index 0000000000..2263871493
Binary files /dev/null and b/docs/Images/cheatsheet1.png differ
diff --git a/docs/Images/cheatsheet2.png b/docs/Images/cheatsheet2.png
new file mode 100644
index 0000000000..ddf97deb27
Binary files /dev/null and b/docs/Images/cheatsheet2.png differ
diff --git a/docs/Images/flashcard class diagram b/docs/Images/flashcard class diagram
new file mode 100644
index 0000000000..451ea9e1d5
--- /dev/null
+++ b/docs/Images/flashcard class diagram
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Images/flashcard class diagram.png b/docs/Images/flashcard class diagram.png
new file mode 100644
index 0000000000..8ffafcde11
Binary files /dev/null and b/docs/Images/flashcard class diagram.png differ
diff --git a/docs/Images/flashcard.drawio b/docs/Images/flashcard.drawio
new file mode 100644
index 0000000000..ce0588e361
--- /dev/null
+++ b/docs/Images/flashcard.drawio
@@ -0,0 +1 @@
+7Vpbj5s4GP01kXYfGoHN9TGXzqz2IlWdSju7LysPOATVwawxTdJfvzbY4RKSgSRkWnUn0gw+mA9zvsN3cWYCF5vdI0Pp+g8aYjIBRribwOUEANcxxG8J7EvAArAEIhaHJWRUwFP8FZegqdE8DnGmsBLilBIep00woEmCA97AEGN025y2oiRsACmKcGMZEngKEMFH0/6MQ74uUQ+4Ff4LjqO1vrPp+OWZDdKTleFsjUK6rUHw/QQuGKW8PNrsFphI7pq8PJw4e1gYwwnvcwH79I/xTH79+ttjsoWzfP+yX/79Tln5gkiuHngCZw8EZesAsfBjnqi1870mRDxGKg/zDfk9XmESJ2I0TzGLN5hjJs4QBX+osPl2HXP8lKJAXroVShHYmm+IGJniUHiPI3EJO4wJQWkWvxR3NQTCcJCzLP6CP+KsFIlEac7lnRYH50vwmBj9lJhxvKtBiqhHTMU62V5M0Wd95TStWjXcVhIwDYWta+4HWu5IyS46mK48Iw6UcwY4Chw7qu2ZGp8pjRNeLMGeT+xly0GU8TWNaIJI3UXHtJ1VTG8uLbtBpdnJ5TGVozFpeqNTuRJyVqHMVMMFJZQVxuHDTH7ux3hPwv2xCIcdfDv/5jLuzVEYyuAtYk2FnfOGJCEW0XlG4igR2AvlnG7ECZyEMxnuJUZo8LmAxOqfVVAoBn+9FiEymrMAn/OFopYjFuFzTlOawmGE+7jsnTE1XJ06GCaIi1DXTGYdblHmPkiJ1oKX3QxeptnybPmU6qp6xtCG9ES6WmWYHwngsPwrXkL79ZfwRKZBUgFxigrXiXOzgMs3661SUFuRnErDmbhPnESf5GAJnVOp6uJAMTyjgaYowHFQAB1BARqjhWG/KywQrmgoSjrNRBUZoAEN27DqkBMVf2tlyxKL91/ZEmsrzalp3185U9cIGFck0GuKxOlb9lijlT0dBeqIyXoYv+d1PXK6tkej3PrhKDeh3YtzbzTOjUGcD6mC+nJN0AsmcxR8jhjNk7A2xVzIj7S+i/mzWoI8LsqpqSmJLsbLnS625GBfG9Scf20B5vUsrGqu1G67sq4C7bqqnRtfrat0mHX9hqF25V0Wl0d2blV7aW3dUGw0xeLUPBQJGIdaIYnezvH6yauvUrUMRclsg4YUfc8bLMVDl2BODeg3OoWp60INVAaL0b4+up26D1tcr7UXvV+DKzUPnZbm3Us1b7YM3Vv0x12o6D0XolrMfvr5VrH2liLXspSdoec0dWkYziW6rF4c34ONF0eEpDvGcNBT5LoSeYNY35YruDjWt5NGe19rbN33aLS/02Dv+/fUrNU3Mts9RVvt/ADTc29ToVgt1Q7e+Tkhf9g2dEK199xCAk6HsntsIBQ/5zcQ/t88uGDzwNY1iY50Hpx2tVUdfZVpwNNSv66xcgeFv2+gmT3IeuT9AzBaLzvs+5W3qq90LzsVkb3RzlpwcFo58U2DCOzWnfuHvllKq2zs/sHyWzstPTPSzZJE1y7z2OXPoWZp1iv2SB1CR+PqmBc1CFcIz+0rvL41/ZXCs82m8IAHblR3i2H1Txvl9Oo/X+D7/wA=
\ No newline at end of file
diff --git a/docs/Images/timetable b/docs/Images/timetable
new file mode 100644
index 0000000000..2f2cb2a2de
--- /dev/null
+++ b/docs/Images/timetable
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Images/timetable_sequence diagram.png b/docs/Images/timetable_sequence diagram.png
new file mode 100644
index 0000000000..5764bbeb73
Binary files /dev/null and b/docs/Images/timetable_sequence diagram.png differ
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..2f06f0d046 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,6 +1,19 @@
-# Duke
+# Study It
-{Give product intro here}
+**Welcome to Study It!**
+
+Study It is an interactive desktop app that helps manage your study related matters,
+optimized for use via a Command Line Interface (CLI). It can keep track of your various study matters,
+present them in an organized and thoughtful manner to help you organize your study life.
+It will also provide various functionalities to help with your studies. You will be able to make full
+use of the application if you can type fast.
+
+This application currently has the following modes that you can access and use:
+1. Menu - Central location of the app
+1. Bookmark - Manage your online links at one convenient location
+1. Timetable - Keep track of your weekly activities
+1. Academic - Track your academic performance and store useful contact information
+1. Flashcard - Memorize your study content better with our built-in flashcard
Useful links:
* [User Guide](UserGuide.md)
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..9b2ba15734 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,1119 @@
# User Guide
-## Introduction
+* Table of Contents
+{:toc}
-{Give a product intro}
+
-## Quick Start
+## Introduction
-{Give steps to get started quickly}
+**Welcome to Study It User Guide!**
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+Study It is an interactive desktop app that helps manage your study related matters,
+optimized for use via a Command Line Interface (CLI). It can keep track of your various study matters,
+present them in an organized and thoughtful manner to help you organize your study life.
+It will also provide various functionalities to help with your studies. You will be able to make full
+use of the application if you can type fast.
+
+This application currently has the following modes that you can access and use:
+1. Menu - Central location of the app
+1. Bookmark - Manage your online links at one convenient location
+1. Timetable - Keep track of your weekly activities
+1. Academic - Track your academic performance and store useful contact information
+1. Flashcard - Memorize your study content better with our built-in flashcard
+
+## About
+This app is targeted towards National University of Singapore (NUS) students studying in this current online
+environment. This user guide will be providing information about how to use the Study It app by
+showing you a step-by-step guide to access each functionality the app provides.
+By utilizing these features, you will be able to manage your study matters efficiently!
+
+The following is a list of common notations and symbols you’ll encounter throughout the user guide:
+
+1. INDEX_NUMBER
+
+ Words of phrases in full capital indicates that they are inputs that you can decide on
+
+1. `command`
+
+ words or phrases highlighted indicate that they are actual commands you can use in the app
+
+1. [website link](https://ay2021s1-cs2113t-t12-1.github.io/tp/UserGuide.html)
+
+ Underlined words or phrases in blue colour are website links that you can press on to access the website
+
+
+
+## Getting Started - *Lim Yuan Bing*
+
+Let’s get started with using Study It! This section will show you how you can run our app on your computer.
+
+Firstly, please ensure that your computer fulfills the following requirement:
+* Has Java 11.0.8
+ * You may refer to this [website](https://www.oracle.com/java/technologies/javase/jdk11-archive-downloads.html) to download the Java 11.0.8 installer
+ * The installation guide can be found in the following websites:
+ * [Windows](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-microsoft-windows-platforms.html#GUID-A7E27B90-A28D-4237-9383-A58B416071CA)
+ , [Linux](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-linux-platforms.html#GUID-737A84E4-2EFF-4D38-8E60-3E29D1B884B8)
+ , [MacOS](https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm)
+
+Once you are done installing Java 11.0.8 onto your PC, you may follow these procedures to start using Study It:
+
+1. Download the tP.jar file from our [Github release](https://github.com/AY2021S1-CS2113T-T12-1/tp/releases) and place it in an empty folder
+1. Open your computer’s command prompt
+ 1. Windows: press Windows key + R, type “cmd” and press Enter
+ 1. MacOS: press Command - spacebar to launch Spotlight and type "Terminal," then double-click the search result
+ 1. Linux Ubuntu: press Ctrl + Alt + T
+1. Change the directory of the command prompt to the folder containing tP.jar file
+1. Type `java -jar tp.jar` into the command prompt and press Enter to execute it
+1. If the application runs successfully, you’ll be greeted by the following welcome message:
+
+
+
+
+
+Congratulations! You are now able to run Study It. To access its various functionalities,
+you would need to type in the command at the Command Prompt and press Enter. Whenever you feel lost,
+refer to the following sections of this User Guide or call the `help` function in the app
+for guidance. We hope that you have fun using our app!
+
+
+
+## General Commands - *Lim Yuan Bing*
+
+The following section details the general commands you can use in the app.
+These commands can be used anywhere in the app to help you navigate around the app.
+
+This section contains the following commands:
+* 1 : [Prints help message](#1-prints-help-message-help)
+* 2 : [Changes the current mode](#2-changes-the-current-mode-cd-mode_name-or-mode_index)
+* 3 : [Shows the current location](#3-shows-the-current-location-location)
+* 4 : [Prints starred items](#4-prints-starred-items-highlight)
+* 5 : [Exits the current mode or application](#5-exits-the-current-mode-or-application-exit)
+
+>**Warning**
+>The general commands doesn't work during `add class` or `add activity` sequence in timetable mode
+>and `add` or `test` sequence in flashcard mode
+
+
+
+### 1. Prints help message: `help`
+
+The app will print out a summarised list of functions you can call at the current mode.
+This help message will vary depending on which mode you are at.
+Use this command to get guidance on what you can do with the app!
+
+Instruction:
+1. Type `help` and press Enter
+
+Expected output:
+
+Example of printing help message at menu:
+
+
+
+
+
+
+
+Another example of printing help message at bookmark mode:
+
+
+
+
+
+>**Useful information:**
+>* The message varies in different modes to show you the commands at that mode.
+>Try it out!
+
+
+### 2. Changes the current mode: `cd MODE_NAME or MODE_INDEX`
+
+You can change to different modes of the app by using this command!
+The following are the modes currently available in the app and their corresponding index:
+1. menu
+1. bookmark
+1. timetable
+1. academic
+1. flashcard
+
+Instruction:
+1. Type `cd` followed by the `MODE_NAME` or `MODE_INDEX`
+1. Press Enter
+
+Expected output:
+
+Command: `cd 2`
+
+
+
+
+
+Command: `cd academic`
+
+
+
+>**Warning**
+>* An error message will appear when you type an invalid mode index or mode name
+>
+>
+>
+>* Ensure that your index is within range or you spelt the mode names correctly when using this command!
+
+>**Useful information:**
+>* You can use this command anywhere in the app to switch between modes quickly!
+>* This command STILL works if you don't have space/have excess space
+>between `cd` and the `MODE_NAME/MODE_INDEX`
+
+
+
+### 3. Shows the current location: `location`
+
+Calling this command will show you which mode you are currently at.
+
+Instruction:
+1. Type `location` and press Enter
+
+Expected output:
+
+At bookmark mode:
+
+
+
+At flashcard mode:
+
+
+
+
+
+### 4. Prints starred items: `highlight`
+
+This command will print out the starred items in Bookmark and Academic
+
+Instruction:
+1. Type `highlight` and press Enter
+
+Expected output:
+
+
+
+
+
+### 5. Exits the current mode or application: `exit`
+
+This command behaves differently depending on which mode you are currently at.
+
+If you are currently at the Main Menu, calling this command will exit the app as shown below:
+
+Instruction:
+1. Type `exit` and press Enter
+
+Expected output:
+
+
+
+If you are in any of the other modes (i.e. bookmark/timetable/academic/flashcard),
+calling this command will exit that mode and place you at the Main menu instead, as shown below:
+
+Instruction:
+1. Type exit and press enter when you are in any other modes besides Main menu
+
+Expected output:
+
+
+
+
## Features
+
+## 1. Bookmark - *Ling Si Hui, Shiho*
+
+Now that more lessons are moving online, are you managing your links well? You might
+want to save your time finding your zoom links in your email inbox and save all your
+links in the bookmark feature to access them easily! The bookmark mode enables you to
+compile all your links in one destination and even categorise them into different groups.
+After entering the bookmark mode (refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index)), use the following commands to
+navigate around bookmark mode.
+
+This section contains 8 commands:
+* 1.1 : [Viewing all bookmark links / starred links / category](#11-viewing-all-the-bookmarks-links-listlist--s-list--c-list--a)
+* 1.2 : [Going into each category](#12-going-into-each-category-bm-number)
+* 1.3 : [Adding a category](#13-adding-category--cat-category_name-)
+* 1.4 : [Deleting a category](#14-deleting-a-category--delete-category_number)
+* 1.5 : [Going back to Bookmark main ](#15-going-back-to-bookmark-main-back)
+* 1.6 : [Adding a link to your chosen category](#16-adding-a-link-to-your-chosen-category-add-link--add-link-t-title)
+* 1.7 : [Deleting a link](#17-deleting-a-link-rm-link_number-)
+* 1.8 : [Starring / Unstarring a link](#18-marking-unmarking-a-link-as-a-starred-link-star-link_number)
+
+>**Warning**
+>If you edit the data file wrongly, the bookmark feature will not be able to take in the correct category name, and links.
+>If you encounter any errors after handling the bookmark data file, refer to [FAQ](#faq)
+
+
+
+
+### 1.1 Viewing all the bookmarks links: `list`,`list -s`, `list -c`, `list -a`
+
+Are you trying to find your links by entering into each category to view your links?
+You might want to have an easy way to view the overview of your links.
+You can now view the entire list of links in the category you are in,
+the starred links, the list of categories available,
+or the entire list of links in every category using the following commands.
+
+Instructions:
+1. If you want to view the list of links in the category you are in = `list`
+2. If you want to view the entire list of starred links = `list -s`
+3. If you want to view the entire list of category available = `list -c`
+4. if you want to view the entire list of links in every category = `list -a`
+
+Expected output:
+
+
+
+
+
+
+>**Useful Information:**
+>* You can only use this command anywhere after entering the bookmark mode. (Refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index))
+>* If your category does not have any links, it will indicate that the list is empty.
+>* If you are in bookmark main, and you input `list`, it will show you the entire list of links in every category. (Same command as `list -a`)
+>* To star / unstar a link refer to [1.8](#18-marking-unmarking-a-link-as-a-starred-link-star-link_number)
+>* To add a category refer to [1.3](#13-adding-category--cat-category_name-), to delete a category refer to [1.4](#14-deleting-a-category--delete-category_number)
+>* You can also omit the space between `list` and `-a` / `-s` / `-c`
+>* The user input is not case-sensitive.
+
+>**Warning**
+>* Follow the format `list`, `list -s`, `list -c`, `list -a` without adding additional inputs. If additional input is detected, the program will prompt you to input the correct format.
+
+
+
+### 1.2 Going into each category: `bm NUMBER`
+
+Managing so many links can be a hassle! However, categorising the links into different
+groups can make it even more efficient to find your links! After entering bookmark mode
+(refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index)), you can enter each category using the following commands.
+This command allows you to change the bookmark category within the bookmark mode.
+
+Instruction:
+1. `bm NUMBER `
+
+E.g. `bm 2`
+Expected output:
+
+
+
+>**Useful Information:**
+>* You can only use this command anywhere after entering the bookmark mode. ( Refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index))
+>* Zoom, Nus, Internship, Hackathon, Career Talks categories are included in the default.
+>* If you are already in the chosen category, the program will inform you as shown in the figure below.
+>
+>* You can also omit the space between `bm` and `NUMBER`
+>* The user input is not case-sensitive.
+
+If you encounter any errors, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that the category NUMBER that you have chosen is valid. Error will be shown if the category NUMBER does not exist, or the NUMBER you have entered is not a number. To find out the valid category NUMBER, view the list of categories (Refer to [1.1](#11-viewing-all-the-bookmarks-links-listlist--s-list--c-list--a))
+
+
+
+### 1.3 Adding category: `cat CATEGORY_NAME `
+
+If you cannot find the perfect category to place your bookmark,
+why not create your own category! In addition to the default categories
+that are added (Zoom, NUS, Internship, Hackathon, Career Talks), create your
+own category to add your bookmark links. Use the following commands to add a category
+and navigate it (Refer to [1.2](#12-going-into-each-category-bm-number)) the same way as the rest of your categories.
+
+Instruction:
+1. `cat CATEGORY_NAME`
+
+e.g. `cat entertainment`, `cat stocks`
+
+Expected output:
+
+
+
+
+>**Useful Information:**
+>* You can only use this command anywhere after entering the bookmark mode. (Refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index))
+>* NUS, Zoom, Internship, Hackathon and Career Talk categories are included in the default.
+>* You can also omit the space between `cat` and `CATEGORY_NAME`
+>* The user input is not case-sensitive.
+
+If you encounter any errors, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that the category name is not empty. Error will be shown if the category name is empty.
+>* You can only add unique category name.
+
+
+
+### 1.4 Deleting a category: `delete CATEGORY_NUMBER`
+
+When you have a category, but you have no important links related to the category, take it out of your bookmark list! Organise and design your bookmark categories to your own personal needs by adding your own category (refer to [1.3](#13-adding-category--cat-category_name-)) and deleting unnecessary categories using these following commands.
+
+Instruction:
+
+1. `delete CATEGORY_NUMBER`
+
+e.g. `delete 6`
+
+Expected output:
+
+
+
+>**Useful Information:**
+>* You can only use this command in bookmark main. (Refer to [1.5](#15-going-back-to-bookmark-main-back) to go back to the bookmark main)
+
+Before deleting a category, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that the category NUMBER that you have chosen is valid. Error will be shown if the category NUMBER does not exist, or the NUMBER you have entered is not a number. To find out the valid category NUMBER, view the list of category available. (Refer to [1.1](#11-viewing-all-the-bookmarks-links-listlist--s-list--c-list--a))
+>* CAUTION: Make sure to check all your links before deleting. Deleting a category will delete all the bookmarks in the category!
+
+
+
+### 1.5 Going back to bookmark main: `back`
+
+There are two modes in bookmark feature: the main bookmark mode (refer to [General Command 2](#2-changes-the-current-mode-cd-mode_name-or-mode_index)),
+and the category mode (Refer to [1.2](#12-going-into-each-category-bm-number)). To navigate freely from mode to mode, use the following command.
+This command goes back to the previous mode depending on which mode you are in.
+
+Instruction:
+1. `back`
+
+Expected output:
+
+
+
+>**Useful Information:**
+>* When you input `back` in any bookmark category, you are brought back to the bookmark main.
+>* When you input `back` in the bookmark main, you will be prompted to type “`exit`” to exit bookmark mode.
+>* The user input is not case-sensitive.
+
+>**Warning:**
+>* Follow the format `back` without adding additional inputs.
+>If additional input is detected, the program will prompt you to input the correct format.
+
+
+
+### 1.6 Adding a link to your chosen category: `add LINK` / `add LINK t->TITLE`
+
+If you have a link to add to your bookmark category, follow these commands.
+Make sure you have chosen your category (Refer to [1.2](#12-going-into-each-category-bm-number))
+and ensure that you do not add an invalid link or an empty link to your bookmark.
+If you are afraid you will forget what the bookmark link is for, you can
+add a title to your bookmark link just by including a ` t-> TITLE` after you enter your link.
+In addition, if you forget what links you have already bookmarked, you can always
+add the same link, and the program will tell you whether you have the link in your list.
+
+Instruction:
+1. `add LINK` e.g. `add google.com`
+2. `add LINK t->TITLE` e.g. `add https://nus-cs2113-ay2021s1.github.io/website/index.html t->Cs2113T`
+
+Expected output:
+
+
+
+
+>**Useful Information:**
+>* You can only use this command after choosing your category. (Refer to [1.2](#12-going-into-each-category-bm-number))
+>* You can only bookmark unique links within your category. Refer to the following figure.
+>
+>* The user input is not case-sensitive.
+
+If you encounter any errors, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that you have chosen a category. You will be prompted to choose a category before you are allowed to add your links. (Refer to [1.2](#12-going-into-each-category-bm-number))
+>* Ensure that the link added is valid. Error will be shown if the link you have given is empty or is not valid (contains " ", "\|" or does not contain “.”).
+
+
+
+### 1.7 Deleting a link: `rm LINK_NUMBER `
+
+If you have a link that you no longer want to bookmark, or if you have a link that you accidentally bookmarked, you can remove the bookmark easily just by following these few commands. Make sure that you have chosen your category (Refer to [1.2](#12-going-into-each-category-bm-number)) and ensure that you do not remove an empty, or an invalid link number.
+
+Instruction:
+1. `rm LINK_NUMBER`
+
+e.g. `rm 1`
+
+Expected output:
+
+
+
+>**Useful Information:**
+>* You can only use this command after choosing your category. (Refer to [1.2](#12-going-into-each-category-bm-number))
+>* You can also omit the space between `rm` and `NUMBER`
+>* The user input is not case-sensitive.
+
+If you encounter any errors, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that you have chosen a category. You will be prompted to choose a category before you are allowed to remove your links. (Refer to [1.2](#12-going-into-each-category-bm-number))
+>* Ensure that the link number that you want to remove is valid. Error will be shown if the link number you have given is empty or is not valid. Refer to [1.1](#11-viewing-all-the-bookmarks-links-listlist--s-list--c-list--a) to find out the correct link number.
+
+
+
+### 1.8 Marking/ Unmarking a link as a starred link: `star LINK_NUMBER`
+
+You might have many links that you need to manage, however, some of the links might be more important than others. If you have such links, you can easily mark them up by following these few commands. Make sure that you have chosen your category (Refer to [1.2](#12-going-into-each-category-bm-number)) and ensure that you do not input an empty or invalid link number.
+
+Instruction:
+1. `star LINK_NUMBER`
+
+e.g. `star 1`
+
+Expected output:
+
+{:width="30%" height="30%"}
+
+>**Useful Information:**
+>* It is the same command for marking and unmarking any links. For example, if link 1 is not starred, star 1 will mark the link as starred. And if link 1 is starred, star 1 will unmark link 1.
+>* You can view your starred links in the highlight function in the main mode. (Refer to [General Command 4](#4-prints-starred-items-highlight))
+>* You can also omit the space between `star` and `NUMBER`
+>* The user input is not case-sensitive.
+
+If you encounter any errors, take note of the following warnings.
+
+>**Warning:**
+>* Ensure that you have chosen a category. You will be prompted to choose a category before you are allowed to mark your links as starred. (Refer to [1.2](#12-going-into-each-category-bm-number))
+>* Ensure that the link number that you want to mark as star is valid. Error will be shown if the link number you have given is empty or is not valid. Refer to [1.1](#11-viewing-all-the-bookmarks-links-listlist--s-list--c-list--a) to find out the correct link number.
+
+
+
+
+## 2. Timetable - *Lin Yuheng*
+Do you find it a hassle to keep track of all your activities and Zoom links for online classes?
+Do you wish there was a simple, visual way to organise your day and foresee any clashes in your schedule?
+The timetable mode intends to address these issues, helping you keep track of your work and helping you achieve
+purposeful productivity.
+
+>**Warning:**
+>* Do not try to edit the data file for the timetable if you are unsure. Doing so may result in the application not being able to
+>retrieved the saved data, hence deem the data file corrupted and request to format the data file before you can use the timetable
+>feature again.
+
+This section contains 10 commands to navigate the Timetable mode:
+* [2.1. Entering timetable mode](#21-entering-timetable-mode-cd-3--cd-timetable)
+* [2.2. Adding classes](#22-adding-classes-add-class)
+* [2.3. Adding activities](#23-adding-activities-add-activity)
+* [2.4. Showing links](#24-showing-links-show-link)
+* [2.5. Showing schedule](#25-showing-schedule-show-schedule)
+* [2.6. Showing activities list](#26-showing-activities-list-list-activity)
+* [2.7. Showing classes list](#27-showing-class-list-list-class)
+* [2.8. Deleting an activity](#28-deleting-an-activity-delete-activity-index)
+* [2.9. Deleting a class](#29-deleting-a-class-delete-class-index)
+* [2.10 Removing all past events](#210-removing-all-past-events-clean-up)
+
+
+
+### 2.1 Entering timetable mode: `cd 3` / `cd timetable`
+
+If you find it difficult to make plans due to uncertainties in your schedule, this timetable mode presents your upcoming
+events at a glance to know what to expect and stay on track. This command brings you to enter the timetable mode.
+
+Instruction:
+
+1. `cd 3` / `cd timetable`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Useful information:**
+>* You can use this command from any mode to access the timetable mode easily and quickly!
+
+
+
+### 2.2 Adding classes: `add class`
+
+If you find it hard to keep track of all your Zoom links with an increasing number of online classes, you can now
+arrange your classes in a systematic manner with this feature. Make sure you are currently in the timetable mode
+([refer to 2.1](#21-entering-timetable-mode-cd-3--cd-timetable)).
+
+Instruction:
+
+1. `add class`
+2. Answer the questions as prompted
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Useful Information:**
+>* The module code will accept any input between 1-7 characters.
+>* You can enter the time in both 12hr and 24hr format. Only entering am/pm at the back of the duration will be assumed
+>as both starting and ending time are in the same period.
+
+
+
+If you encounter any errors, take note of the following warning.
+
+>**Warning:**
+>* Ensure that you follow the format for answering the questions.
+>Error will be shown if the questions are not answered in a suitable format.
+>* Adding events that clash with the existing schedule will result in error message. You will need to check through
+>the schedule and events list and delete the unwanted event accordingly before you can add the new event.
+>* Number of recurring classes are capped at 52 weeks (1 year) to ensure effective processing time. Add your class again one year
+>later if your class recurs for more than a year.
+
+
+
+### 2.3 Adding activities: `add activity`
+
+It can be hard to view your upcoming events at a glance.
+Similar to the previous feature, this command allows you to add activities outside of classes to your schedule.
+
+Instruction:
+
+1. `add activity`
+2. Answer the questions as prompted
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Useful Information:**
+>* Currently this feature does not support adding activity past 12am. If you wish to schedule an activity overnight,
+>add the activity in 2 separate sessions.
+
+
+
+### 2.4 Showing links: `show link`
+
+If you find it hard to keep track of all your conference links for your classes or activities, this command will present
+all links relevant to you for the next 2 hours.
+
+Instruction:
+1. `show link`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+
+
+### 2.5 Showing schedule: `show schedule`
+
+If you wish to view your schedule for the next seven days with all the activities, use this command.
+
+Instruction:
+1. `show schedule`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Warning:**
+>* If the name of event is more than 10 character only the first 10 character will be shown.
-{Give detailed description of each feature}
+
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+### 2.6 Showing Activities list: `list activity`
-Format: `todo n/TODO_NAME d/DEADLINE`
+If you wish to see all activities you have input into the system,
+this command will present all the activities you have added with their starting date and time, if the activity is
+online, and the venue/link of the activity.
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+Instruction:
+1. `list activity`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+### 2.7 Showing Class list: `list class`
+
+If you think searching through the timetable is too troublesome,
+use this command to see all the classes you have added and other details of the classes, similar to the previous feature.
+
+Instruction:
+1. `list class`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+
+
+### 2.8 Deleting an activity: `delete activity INDEX`
+
+If you have accidentally added a wrong activity, or an activity you have added has been cancelled,
+use this command to delete an activity with corresponding index according to the activities list ([refer to 2.6](#26-showing-activities-list-list-activity)).
+
+Instruction:
+1. `delete activity INDEX`
+
+Example of usage:
+
+`delete activity 1` will delete the first activity in the list.
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+### 2.9 Deleting a class: `delete class INDEX`
+
+Similar to feature 2.8,
+use this command to delete a class with corresponding index according to the classes list ([refer to 2.7](#27-showing-class-list-list-class)).
+
+Instruction:
+1. `delete class INDEX`
Example of usage:
-`todo n/Write the rest of the User Guide d/next week`
+`delete class 2` will delete the second class in the list.
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Warning:**
+>* Deleting a class will delete all the lessons of that module on schedule. Use this command with caution.
+
+
+
+### 2.10 Removing all past events: `clean up`
+
+Having too many events added to the application, and the data file is taking up too much space?
+Use this command to remove all the activities that was over more than 7 days ago and all the classes with their last lesson
+concluded more than 7 days ago.
+
+Instruction:
+1. `clean up`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Warning:**
+>* Deletion will be done automatically. All the events that are deleted will not be able to be retrieved.
+>Only use this if you are sure you do not need your past events.
+
+
+
+
+
+## 3. Academic - *Lu Ziyi*
+
+Have you ever had to dig through tons of emails to look for the contact of a particular TA
+or sweat over your calculator when trying to estimate your CAPS this semester?
+Academic tracker provides a convenient experience where you can store
+all the information you need in one place! To access the academic tracker,
+follow the instructions below.
+
+This section contains 12 commands to navigate the academic mode:
+* [3.1 Entering Academic Mode](#31-entering-academic-mode-cd-4--cd-academic)
+* [3.2 Adding a contact](#32-adding-a-contact-add-contact-ccontact_details-mmobile_number--eemail)
+* [3.3 Listing all contacts](#33-listing-all-contacts-list-contact)
+* [3.4 Starring a contact](#34-starring-a-contact-star-contact-index)
+* [3.5 Deleting a contact](#35-deleting-a-contact-delete-contact-index)
+* [3.6 Adding a grade](#36-adding-a-grade-add-grade-nmodule_name--mmc--ggrade)
+* [3.7 Listing all grades](#37-listing-all-grades-list-grade)
+* [3.8 Checking current cap](#38-checking-current-cap-check-cap)
+* [3.9 Starring a grade](#39-starring-a-grade-star-grade-index)
+* [3.10 SU-ing a grade](#310-su-ing-a-grade-su-grade-index)
+* [3.11 Deleting a grade](#311-deleting-a-grade-delete-grade-index)
+* [3.12 Listing all the starred items in academic](#312-listing-all-the-starred-items-in-academic-list-star)
+
+
+
+### 3.1 Entering Academic Mode: `cd 4` / `cd academic`
+
+This command allows you to enter academic tracker mode from the main menu or from the other modes.
+After entering this mode, you can then access all the features that the academic tracker offers!
+
+Instruction:
+
+1. `cd 4` / `academic`
+
+Expected output:
+
+
+
+>**Useful information:**
+>* You can use this command from any mode to access the academic mode easily and quickly!
+
+
+
+### 3.2 Adding a contact: `add contact c/CONTACT_DETAILS m/MOBILE_NUMBER e/EMAIL`
+
+In academic mode, you can add a contact to the current list of contacts, following the instructions below.
+
+Instruction:
+1. `add contact c/CONTACT_DETAILS m/MOBILE_NUMBER e/EMAIL`
+
+Example of usage:
+
+`add contact c/Prof Lim m/81234567 e/E7654321@u.nus.edu`
+will add a contact with the name Prof Lim, mobile number 81234567, and email E7654321@u.nus.edu.
+
+Expected output:
+
+
+
+>**Warning:**
+>* Numbers should be a positive integer with 8 or fewer digits , and email should be in the form abc@xyz.
+
+
+
+### 3.3 Listing all contacts: `list contact`
+
+You can view all the contacts that have been added previously
+and stored on your computer by following these sets of instructions
+
+Instruction:
+1. `list contact`
+
+Expected output:
+
+
+
+### 3.4 Starring a contact: `star contact INDEX`
+
+Sometimes you may wish to highlight an important contact, and that's where
+starring a contact come into use. Follow the instructions below to mark an
+important contact with a star.
+
+Instruction:
+1. `star contact INDEX`
+
+Example of usage:
+
+`star contact 1` will mark the first contact in the list with a star.
+
+Expected output:
+
+
+
+
+
+### 3.5 Deleting a contact: `delete contact INDEX`
+
+Do you no longer require the contact of the TA of last sem's module?
+Make use of the delete contact function to clean up your contacts by following the
+instructions below.
+
+Instruction:
+1. `delete contact INDEX`
+
+Example of usage:
+
+`delete contact 1` will delete the first contact in the list.
+
+Expected output:
+
+
+
+
+
+### 3.6 Adding a grade: `add grade n/MODULE_NAME m/MC g/GRADE`
+
+In academic mode, you can add a grade to the current list of grades, following the instructions below.
+
+Instruction:
+1. `add grade n/MODULE_NAME m/MC g/GRADE`
+
+Example of usage:
+
+`add grade n/CS2101 m/4 g/A-`
+will add a grade with the title CS2101 that has 4 credits and scored an A-.
+
+Expected output:
+
+
+
+>**Warning:**
+>* Note that module credits need to be a positive integer, and grade entered must be a valid grade.
+>* This program doesn't cap how many MCs a module can have.
+>* This application is not synced to a module database, so any valid input will be accepted as a module name.
+
+### 3.7 Listing all grades: `list grade`
+
+You can view all the grades that have been added previously
+and stored on your computer by following these sets of instructions
+
+Instruction:
+1. `list grade`
+
+Expected output:
+
+
+
+
+
+### 3.8 Checking current cap: `check cap`
+
+To calculate your current CAP based on the grades you have entered previously,
+follow the instructions below
+
+Instruction:
+1. `check cap`
+
+Expected output:
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+
-## FAQ
+### 3.9 Starring a grade: `star grade INDEX`
+
+The star grade function can be used to highlight a particular grade.
+Follow the instructions below to mark an
+important grade with a star.
+
+Instruction:
+1. `star grade INDEX`
+
+Example of usage:
+
+`star grade 1` will mark the first grade in the list with a star.
+
+Expected output:
+
+
+
+
+
+### 3.10 SU-ing a grade: `su grade INDEX`
+
+SU-ed a module and want to exclude it from your CAP calculation? The SU grade
+function allows you to do just that through these simple steps.
+
+Instruction:
+1. `su grade INDEX`
+
+Example of usage:
+
+`su grade 1` will su the first grade in the list.
+
+Expected output:
+
+
+
+>**Warning:**
+>* The process of SU-ing a mod is not retractable. Should you accidentally SU a mod unintentionally,
+>consider deleting the mod and adding a new one.
+
+
+
+### 3.11 Deleting a grade: `delete grade INDEX`
+
+The delete grade function can be used to delete a grade from the currently stored
+ list of grades by following the instructions below.
+
+Instruction:
+1. `delete grade INDEX`
+
+Example of usage:
+
+`delete grade 1` will delete the first grade in the list.
+
+Expected output:
+
+
+
+### 3.12 Listing all the starred items in academic: `list star`
+
+The list star function works like the highlight function, but only displaying
+the starred items inside the academic section.
+
+Instruction:
+1. `list star`
+
+Expected output:
+
+
+
+
+
+## 4. Flashcard - *Lim Si Qiao Florence*
+
+Do you wish you had a quick way to refer to the content that will be tested in your upcoming tests?
+Or a more efficient way to verify your knowledge?
+Perhaps it is also difficult to scour your handwritten notes to find a particular piece of information.
+The flashcard mode aims to tackle these aspects that may hinder your learning process.
+
+This section contains 6 commands to navigate the Flashcard mode:
+* [4.1. Entering flashcard mode](#41-entering-flashcard-mode-cd-5--cd-flashcard)
+* [4.2. Adding flashcards](#42-adding-flashcards-add)
+* [4.3. Listing flashcards](#43-listing-flashcards-list)
+* [4.4. Deleting flashcards](#44-deleting-flashcards-delete)
+* [4.5. Testing content](#45-testing-contenttest)
+* [4.6. Finding relevant flashcards](#46-finding-relevant-flashcards-find)
+
+### 4.1 Entering flashcard mode: `cd 5` / `cd flashcard`
+
+If you find it hard to be fully proficient in your study topics, this flashcard mode is a medium for you to actively
+learn and memorise. This enables you to learn effectively through repetition, helping you to remember information better
+in the long-term. This command allows you to enter the flashcard mode.
+
+Instruction:
+1. `cd 5` / `cd flashcard`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Useful information:**
+>* You can use this command from any mode to access the flashcard mode easily and quickly!
+
+
+
+### 4.2 Adding flashcards: `add`
+
+To assist you in your studies, there needs to be a knowledge base of content to be revised.
+You can do this by adding new flashcards to the flashcard deck with this command, after entering flashcard mode
+([refer to 4.1](#41-entering-flashcard-mode-cd-5--cd-flashcard)).
+
+Instruction:
+1. `add`
+2. Enter the question and answer as prompted
+
+Example of usage:
+
+`4+4` followed by `8` will create a flashcard with question 4+4 and answer 8.
+
+Expected output:
+
+{:height="65%" width="65%"}
+
+If you encounter any errors, take note of the following warning.
+
+>**Warning:**
+>* “back” and "show answer" cannot be added as an answer for the flashcard.
+>This is because “back” and "show answer" are used as commands to exit and reveal the answer in the test mode
+>respectively.
+>If the flashcard answer you wish to use is similar to “back” or "show answer", rephrase and use another term.
+>
+>{:height="60%" width="60%"}
+
+
+
+### 4.3 Listing flashcards: `list`
+
+If you wish to review the content that is currently in the flashcard deck, this command can display all flashcards that
+have been added.
+
+Instruction:
+1. `list`
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+
+
+### 4.4 Deleting flashcards: `delete`
+
+When you have a flashcard that is no longer relevant to you or contains wrong information, you can delete the flashcard
+from the flashcard deck.
+
+Instruction:
+1. `delete`
+2. Enter the card index of the flashcard to be deleted as prompted
+
+Example of usage:
+
+`3` will delete the 3rd flashcard in the list.
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+>**Useful information:**
+>* You can use the `list` command to check the card index.
+
+
+
+### 4.5 Testing content:`test`
+
+Grading your own work is one of the best ways to revise as it helps you effectively retain information.
+After adding the flashcards, you may wish to revise the content by testing yourself.
+
+If you are unable to answer a question and wish to refer to the answer, use `show answer`.
+When you are done revising, use `back` to exit the test mode, and return to the flashcard main.
+
+Instruction:
+1. `test`
+2. Answer the questions as prompted
+3. `show answer` / `back`
+
+Expected output:
+
+{:height="60%" width="60%"}
+
+>**Useful information:**
+>* User input in the test mode is not case sensitive. If the answer is correct but the case is different from
+>the stored answer, the answer will be accepted as the right answer.
+
+
+
+### 4.6 Finding relevant flashcards: `find`
+
+If you wish to look through the flashcards containing only a particular search term, use this command.
+
+Instruction:
+1. `find`
+2. Enter the desired search term as prompted
+
+Expected output:
+
+{:height="80%" width="80%"}
+
+
+
+## FAQ - *Ziyi & Si Hui*
+
+*Lu Ziyi*
**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+**A**: All of Study It's data is stored under the `ROOT_FOLDER/data` folder.
+To transfer these data to another computer, please back up the `data` folder
+and copy it over to the directory in the new computer accordingly after installing the app.
+
+**Q**: Why is my application not starting up properly?
+
+**A**: Please refer to the ["Getting Started"](#getting-started) section and ensure that
+the correct version of java is installed on your computer. If you face any further difficulties,
+feel free to refer to the About Us page and contact any of the developers.
+
+**Q**: Why is XXX feature not supported?
+
+**A**: As this app is still under development, there are many features we would like to add in the future.
+Do feedback to us what features you would like to see in Study It!
+
+*Ling Si Hui, Shiho*
+
+**Q**: What to do if bookmark data does not load properly after changing the bookmark.txt file?
+
+**A**: This is for users who edited the bookmark.txt file in the data folder. If you encounter trouble after editing the data file,
+you can do one of the following steps:
+* revert the changes in the data file.
+* delete the bookmark data file.
+* ensure the bookmark data file are stored in the correct format. This is the following format:
+ * CategoryName = links \| links \| \|STAR\|links \| links t->title
+ * Category name and the links are separated with a " = " and each link is separated with a " \| ". (Take note of the space before and after the symbols)
+ * A starred link has \|STAR\| in front of the link. A link with a title has " t->" infront of the title. (Take note of the space in front of t->)
+
+
+
+## Command Summary - *Lim Yuan Bing*
+
+The following table is a compiled list of all available commands in our application that you can easily refer to!
+
+The commands listed under the sections besides “General” can only be called when you are in that specific mode,
+which you can access using the cd command!
+
+
Table: Command Cheatsheet for Study It
-## Command Summary
+
+
+
-{Give a 'cheat sheet' of commands here}
+
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+
+
+
\ No newline at end of file
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..cc35c1df2c
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-modernist
\ No newline at end of file
diff --git a/docs/team/farice9.md b/docs/team/farice9.md
new file mode 100644
index 0000000000..ed477cc774
--- /dev/null
+++ b/docs/team/farice9.md
@@ -0,0 +1,86 @@
+# Lim Yuan Bing - Project Portfolio Page
+
+## Project: Study it
+
+Study It is an interactive all-in-one study companion to help you organize your study matters!
+
+It is packed with 4 major features: bookmark, timetable, academic and flashcard to help store and arrange your
+study matters in a thoughtful manner so that you can focus on Studying It!
+
+The following are my contributions to the project!
+
+### Features added:
+
+* **Designed the main architecture of the program and maintain it**
+ * What it does: Provides proper partitioning and command parsing as well as program flow to ensure every team member's
+ code can be fit into our program. I have also helped integrated each member's mode into the program.
+ * Justification: For a program with 4 major features, I needed to design the architecture such that user can switch
+ between the modes seamlessly and use the functionalities provided in each mode without clashing with the rest.
+ * Highlights: With the main architecture, the infrastructure within each mode will not interfere with one another,
+ and the design is flexible enough to implement new features for future expansions.
+ * Credits: The architectural code was coded from scratch.
+
+* **Implemented general functions for the program**
+ * Functions: `help`, `location`, `cd`, `exit`
+ * What it does: These functions can be used anywhere throughout the program to help user navigate our app containing
+ multiple modes. `help` instructs the user what commands are available in each mode. `location` informs the user
+ their current mode. `cd` is used to switch between modes. `exit` is used to either exit the program or their current mode
+ * Justification: We needed general functions to help user navigate our expansive app that has 4 major modes.
+ * Highlights: `help` will print out help messages specific to the mode the user is currently at. `cd` can be used
+ anywhere in the app and is modified to take in index number (for quicker navigation) or mode name (for meaningful interaction).
+ * Credits: The general functions are implemented during the design of the system architecture.
+
+
+
+* **Streamlined the user interface of the program**
+ * What it does: Decided how the general user interface of the program should look like and helped streamlined it across
+ multiple modes.
+ * Justification: A clean user interface will improve the user's experience while using our application.
+ * Highlights: Provided some thoughtful functionality when designing user interface, such as printing the current time
+ at the menu.
+ * Credits: Mode specific interfaces were coded by each respective teammates and streamlined by me.
+
+* **Added `highlight` function as one of the general functions**
+ * What it does: It prints out the starred items from bookmark mode and academic mode
+ * Justification: Allows user to quickly access the important informations he/she deemed important
+ * Highlights: It can be called from anywhere in the app, allowing quicker access
+ * Credits: Si Hui implemented the `star` function in bookmark mode but I implemented it within the academic mode which was
+ designed by Ziyi. I made use of these 2 functionalities to run the `highlight` function.
+
+### Code contributed:
+
+[RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=farice&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=farice9&tabRepo=AY2021S1-CS2113T-T12-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other)
+
+### Project management
+
+* Helped review many PRs and solved several merge conflicts.
+* Made notices for my teammates when issues were found: [checkstyle errors](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/39)
+* Helped my teammates out when they had problems with uploading images to documentations and problems with git.
+* Handled the finalizing and release of our project for each milestone: [Releases](https://github.com/AY2021S1-CS2113T-T12-1/tp/releases)
+
+### Documentation:
+* User Guide:
+ * Added the [About](https://ay2021s1-cs2113t-t12-1.github.io/tp/UserGuide.html#about), [Getting Started](https://ay2021s1-cs2113t-t12-1.github.io/tp/UserGuide.html#getting-started),
+ [General Commands](https://ay2021s1-cs2113t-t12-1.github.io/tp/UserGuide.html#general-commands) sections
+ * Added the [Command Summary](https://ay2021s1-cs2113t-t12-1.github.io/tp/UserGuide.html#command-summary) of the program
+
+* Developer Guide:
+ * Added the [Setting up & getting started](https://ay2021s1-cs2113t-t12-1.github.io/tp/DeveloperGuide.html#setting-up--getting-started),
+ [Major components](https://ay2021s1-cs2113t-t12-1.github.io/tp/DeveloperGuide.html#major-components),
+ [Architecture](https://ay2021s1-cs2113t-t12-1.github.io/tp/DeveloperGuide.html#architecture),
+ [Main component](https://ay2021s1-cs2113t-t12-1.github.io/tp/DeveloperGuide.html#main-component) sections.
+ * Drawn the regular diagrams of major components and system architecture, UML sequence diagram of how the architecture
+ components interact with each other and the UML diagram of the main components in StudyIT class.
+
+
+
+### Community:
+* Non-trivial PR reviews:
+ * [#102](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/102)
+ * [#92](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/92)
+ * [#194](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/194)
+
+* Reported bugs and suggestions to teammates:
+ * [#190](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/190)
+ * [#133](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/133)
+ * [#60](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/60)
\ No newline at end of file
diff --git a/docs/team/flsq.md b/docs/team/flsq.md
new file mode 100644
index 0000000000..48134e28e9
--- /dev/null
+++ b/docs/team/flsq.md
@@ -0,0 +1,66 @@
+# Florence - Project Portfolio Page
+
+## Overview of Project: Study It
+Study It is an interactive desktop app that helps manage your study related matters, optimized for use via a Command
+Line Interface (CLI). It can keep track of your various study matters, presenting them in an organized and thoughtful
+manner to help you efficiently study it with Study It.
+
+It is written in Java, and comprises four main modes: Bookmark, Timetable, Academic and Flashcard.
+
+The following are my contributions to the project.
+
+### Features added:
+
+* **Added the feature to add/delete flashcards**
+ * What it does: Allows the user to add and delete flashcards, based on the question and answer provided by the user.
+ * Justification: This feature improves the product significantly as the user can create a knowledge base of content
+ to be revised, effectively compiling all the information needed for their next test.
+ * Highlights: This feature allows users to add questions and answers according to the self-explanatory prompts by
+ the app, making it an intuitive experience.
+
+* **Implemented the function to list flashcards**
+ * What it does: Lists all the flashcards that the user has added
+ * Justification: This function is necessary for the user to refer to all the flashcards currently in the deck.
+ * Highlights: This function clearly displays the card indexes along with the questions and answers, which is
+ required for deletion of flashcards.
+
+* **Implemented the function to test flashcards**
+ * What it does: Returns a random question from the flashcard deck, and prompts user to enter an answer. The user can
+ quit the test mode with the `back` command, and reveal the answer with the `show answer` command.
+ * Justification: The best way the user can revise their study materials is by grading their own work, effectively
+ helping them retain information and improve their grades.
+ * Highlights: This feature has thoughtful functionalities, such as a way for users to find out the answer
+ immediately when they are unable to answer a question, helping them save time while revising. The score feature also
+ acts as an encouragement for revision. For the convenience of the user, the test mode ignores the case of the user's
+ answers.
+
+* **Implemented the function to find flashcards**
+ * What it does: Returns a list of flashcards that matches the search term input by the user.
+ * Justification: This feature enhances the product because it conveniently returns only the flashcards that the user
+ is interested in.
+ * Highlights: This feature is user-friendly as it is not case sensitive, effectively returning all the flashcards
+ that the user wishes to find.
+
+### Code Contributed:
+
+[RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#search=&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&zFR=false&tabAuthor=hailqueenflo&tabRepo=AY2021S1-CS2113T-T12-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code)
+
+### Documentation:
+
+* User Guide:
+ * Added the documentation for all the commands in flashcard mode, listed under section 4 of the User Guide.
+ * Did cosmetic tweaks to existing documentation of features
+
+* Developer Guide:
+ * Added the implementation details for the flashcard component, including the UMLs used in that section.
+
+### Community:
+
+ * Reported bugs and suggestions to teammates:
+ * [#127](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/127)
+ * [#137](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/137)
+
+ * Reported bugs and suggestions for other teams in the class:
+ * [#2](https://github.com/hailqueenflo/ped/issues/2)
+ * [#4](https://github.com/hailqueenflo/ped/issues/4)
+
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/lingsihui.md b/docs/team/lingsihui.md
new file mode 100644
index 0000000000..156721f91e
--- /dev/null
+++ b/docs/team/lingsihui.md
@@ -0,0 +1,58 @@
+# Ling Si Hui, Shiho - Project Portfolio Page
+
+## Overview
+
+Our product Study It provides an interactive desktop app to help manage your study related matters.
+It can keep track of your various study matters, present them in an organized and thoughtful manner to
+help you organize your study life. It is written in Java and includes 4 features: bookmark, timetable, academic, and flashcard.
+
+Given below are my contributions to the project.
+
+### Features added:
+
+* **New Feature** : Added the ability to add link t-> title/ remove link / add category / delete category / star bookmark
+ * What it does: allows the user to add bookmark link to bookmark list. Links added can be removed by using the remove command. Added links that are important can be starred.
+ * Justification: This feature serves as the basic command for the bookmark feature so that the user can customise the list of links, categories and their starred links.
+ * Highlights: This feature was relatively simple yet tedious. The concept behind the implementation for add links was simple, however, the additional conditions such as including
+ the title for the links, deciding on the factor that makes the link valid, and checking whether the link already exist make the add link command challenging. Add category command follows
+ the same structure as the add link commands but with fewer conditions hence it was less challenging. Delete category command and remove
+ category command have the similar structure with fewer conditions, hence it was less challenging as well. Star command was an additional enhancement that was made afterwards, and the
+ challenging component for star command is that this enhancement affected the rest of the bookmark features, hence it required me to change existing feature.
+ * Credits: The program was coded from scratch but mainly adapting the design architecture from my [ip](https://github.com/lingsihui/ip).
+
+* **New Feature** : Added the ability to change mode/ go back to bookmark main /list bookmark
+ * What it does: allows the user to change mode and go back to main within bookmark feature. The list command was enhanced to show which mode the users are in and how many links they have.
+ * Justification: This features make the navigability within the bookmark feature easier.
+ * Highlights: This feature was challenging in the sense that due to the different modes, the user needs to know the mode of the bookmark mode to better navigate around bookmark feature. This was done through
+ the list command where it shows the current mode the user is currently in and enhancing list command to show the overview of the links, list of categories, list of links in the current mode the user is in and
+ the list of starred links the user has.
+ * Credits: The program was coded from scratch.
+
+* **New Feature** : Added the ability to store bookmark links in file
+ * What it does: allows the user to keep the list of bookmark even after exiting the program.
+ * Justification: This feature is required so that user do not need to input the list of links they want to bookmark every time they start the program.
+ * Highlights: The most challenging part of the feature was to decide on how to separate out the category, title and the links as links can contain many symbols.
+ * Credits: The program was coded from scratch.
+
+### Code Contributed:
+
+[RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=lingsihui&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+### Project Management:
+
+* Logging [#76](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/76)
+* Maintaining the issue tracker
+* Update developer guide documenting the target user profile, user stories, and the documentation section [#118](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/118/files)
+
+### Documentation:
+
+* User Guide:
+ * Added documentation for bookmark features [#137](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/137)
+* Developer Guide:
+ * Added documentation for bookmark feature: included UML diagram of the bookmark feature class diagram, bookmark feature sequence diagram and add command sequence diagram [#102](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/102)
+
+### Community:
+
+* PR Reviewed (with non-trivial comments): [#103](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/103), [#92](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/92)
+* Reported bugs and suggestions for other teams in the class [#2](https://github.com/lingsihui/ped/issues/2), [#3](https://github.com/lingsihui/ped/issues/3), [#4](https://github.com/lingsihui/ped/issues/4), [#5](https://github.com/lingsihui/ped/issues/5), [#6](https://github.com/lingsihui/ped/issues/6), [#7](https://github.com/lingsihui/ped/issues/7)
+
diff --git a/docs/team/luziyi9898.md b/docs/team/luziyi9898.md
new file mode 100644
index 0000000000..df31b541d0
--- /dev/null
+++ b/docs/team/luziyi9898.md
@@ -0,0 +1,59 @@
+# Lu Ziyi - Project Portfolio Page
+
+## Overview
+
+Study It is an interactive desktop app that helps students manage their study related matters,
+optimized for use via a Command Line Interface (CLI).
+Given below are my contributions to the project.
+
+### Features added:
+
+* Designed the structure of the academic mode.
+ * What it does: allows the user to access all the different features in academic mode.
+ * Justification: it is the main framework for the entire academic mode, and facilitates all the various functions.
+ * Highlights: it is a very flexible framework that allows for new features to be added easily.
+ * Credits: the program was coded from scratch.
+
+* Added the function to manage contacts
+ * What it does: allows user to add, delete, check and mark out contacts.
+ * Justification: as an all-in-one academic helper, the ability to keep track of important contacts of professors
+ and TAs is very helpful to students using this app.
+ * Highlights: there is a clear structure in the different segments of the codes(i.e. PersonBook & Person),
+ thus modifications and additions can be made easily without affecting how other functions work.
+ * Credits: the program was coded from scratch, but the star contact segment was added by Yuan Bing.
+
+* Added the function to manage grades
+ * What it does: allows user to add, delete, check and mark out grades, as well as su a grade and check his/her CAP.
+ * Justification: it is important for students to keep track of their grades throughout their course in university,
+ and study it lets the student do that with ease.
+ * Highlights: the app can calculate CAP accurately, taking into consideration factors like module credits, grades,
+ and SUs.
+ * Credits: the program was coded from scratch, but the star grade segment was added by Yuan Bing.
+
+
+
+### Code contributed:
+
+[RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=luziyi9898&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=luziyi9898&tabRepo=AY2021S1-CS2113T-T12-1%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code)
+
+### Documentation:
+* User Guide:
+ * Added documentation for all the commands in academic mode, listed under section 3 of the user guide.
+ * Added documentation for FAQ segment.
+
+* Developer Guide:
+ * Added the implementation details academic component, including the UMLs used in that section.
+
+### Community:
+
+* PR Reviewed(with non-trivial review comments):
+[ [#99](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/99) ]
+[ [#205](https://github.com/AY2021S1-CS2113T-T12-1/tp/pull/205) ]
+
+* Added issues for bugs found in other's sections:
+[ [#108](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/108) ]
+[ [#109](https://github.com/AY2021S1-CS2113T-T12-1/tp/issues/109) ]
+
+* Found significant issues in other group's project:
+[ [#9](https://github.com/luziyi9898/ped/issues/9) ]
+[ [#7](https://github.com/luziyi9898/ped/issues/7) ]
\ No newline at end of file
diff --git a/docs/team/slightlyharp.md b/docs/team/slightlyharp.md
new file mode 100644
index 0000000000..5e84477f7c
--- /dev/null
+++ b/docs/team/slightlyharp.md
@@ -0,0 +1,84 @@
+# Lin Yuheng - Project Portfolio Page
+
+## Project: Study it
+
+Study It is an interactive desktop app that helps students manage their study related matters,
+optimized for use via a Command Line Interface (CLI).
+
+It encompasses 4 main features: bookmark, timetable, academic tracker and flashcard
+to help student organise their study life.
+
+Given below are my contributions to the project.
+
+### Features added:
+
+* **New Feature:** Design and implemented the timetable mode
+
+ * **Sub feature:** Added add class and add activity command
+ * What it does: Allow user to add class or activities to the application. Class
+ are design for recurring events with zoom link or venue attached to it while activity
+ are design for a one off event.
+ * Justification: This feature serves as the basic command for the timtable feature so
+ that the user can plan their schedule.
+ * Highlights: This feature is design with a data structure to store all the information
+ needed by a recurring classes, or a one off activity and arrange these data in a way that is
+ easy to access given a specific date. This feature also required extensive use of LocalDateTime Class
+ to have the saved data to interact real time. There is also extensive error handling involve in the feature
+ to ensure most invalid user input can be handled. Further more there is mathematical calculation involved in finding
+ the dates of lesson for recuring classes base on the user input.
+ * Credits: The code was coded from scratch.
+
+ * **Sub feature:** Added show schedule command
+ * What it does: Display the full schedule the user has planned for the next seven days
+ * Justification: This feature serve as the basic command for the user to view the activities and classes
+ for the next seven days
+ * Highlights: This feature was challenging as a fix table needed to be printed without the help of GUI classes.
+ Initially the table was design to be printed horizontally however the result tend to differ with different
+ command prompt window size. Hence, a vertical table is used and rotation of array is needed for the data to be
+ displayed correctly. Correct data can be easily retrieved due to the data structure of the class and activity
+ designed previously.
+ * Credits: The code was coded from scratch.
+
+ * **Sub feature:** Added show link command
+ * What it does: Allow users to see the links they need, or the venue they need to go to for the next two hours.
+ * Justification: This feature allows the user to experience the ease of accessing links they need for events
+ during the COVID period when many links needed to be managed for school and work.
+ * Highlight: This feature is simple to implement with help of LocalDateTime class,
+ yet it is a really useful feature for students having online lesson during the Covid period
+ * Credits: The code was coded from scratch
+
+ * **Sub feature:** Added list class, list activity, delete class, and delete activity command
+ * What it does: Allow user to see the full list of activities/classes the user has added and delete any unwanted once.
+ * Justification: This feature allows user to see the full list of event so that they can amend any unwanted ones.
+ *Credits: The program was coded from scratch but mainly adapting the design architecture from ip.
+
+ * **Sub feature:** Added clean up command
+ * What it does: allow user to clean up events that are over more than seven days ago
+ *Justification: This feature allows user to free up storage space by deleting all overed event with a single command,
+ so that user do not have to mannually delete overed event which are taking up storage spaces but is not
+ used anymore.
+ * Credits: The code was coded from scratch
+
+### Code contributed:
+
+[RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=slightlyharp&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+### Project Management
+* Reviewed and approved a number of PRs.
+* Set up the PR structure my team on github so that the PRs have to be view by others before merging into master.
+* Set up some Issue for team to work on.
+* Managed and closed some of the Issues and Milestones.
+
+### Documentation:
+* [User Guide:](../UserGuide.md)
+ * Added documentation for all the commands in timetable mode, listed under section 2 of the User Guide.
+
+* [Developer Guide:](../DeveloperGuide.md)
+ * Added the implementation details timetable component, including the UMLs used in that section.
+
+### Community:
+* Reported bugs and suggestions for other teams in the class
+[#1](https://github.com/slightlyharp/ped/issues/1)
+[#2](https://github.com/slightlyharp/ped/issues/2)
+[#3](https://github.com/slightlyharp/ped/issues/3)
+[#4](https://github.com/slightlyharp/ped/issues/4)
diff --git a/src/main/java/academic/AcademicCommandParser.java b/src/main/java/academic/AcademicCommandParser.java
new file mode 100644
index 0000000000..ba4ed92f7a
--- /dev/null
+++ b/src/main/java/academic/AcademicCommandParser.java
@@ -0,0 +1,171 @@
+package academic;
+
+import exceptions.InvalidCommandException;
+import exceptions.InvalidGradeException;
+import exceptions.InvalidMcException;
+import studyit.CommandParser;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ *Parses user inputs for academic mode.
+ */
+public class AcademicCommandParser extends CommandParser {
+ /**
+ * Takes in an input command to and return which type of academic command it falls under.
+ * @param command input command from the user.
+ * @return command type
+ * @throws InvalidCommandException if command type is invalid
+ */
+ public static AcademicCommandType getAcademicCommandType(String command)
+ throws InvalidCommandException {
+ String commandModified = CommandParser.standardizeCommand(command);
+
+ if (commandModified.startsWith("add contact")) {
+ return AcademicCommandType.ADD_CONTACT;
+ } else if (commandModified.equals("list contact")) {
+ return AcademicCommandType.LIST_CONTACT;
+ } else if (commandModified.startsWith("add grade")) {
+ return AcademicCommandType.ADD_GRADE;
+ } else if (commandModified.equals("check cap")) {
+ return AcademicCommandType.CHECK_CAP;
+ } else if (commandModified.equals("list grade")) {
+ return AcademicCommandType.LIST_GRADE;
+ } else if (commandModified.startsWith("delete contact")) {
+ return AcademicCommandType.DELETE_PERSON;
+ } else if (commandModified.startsWith("delete grade")) {
+ return AcademicCommandType.DELETE_GRADE;
+ } else if (commandModified.startsWith("su grade")) {
+ return AcademicCommandType.SU_GRADE;
+ } else if (commandModified.startsWith("star grade")) {
+ return AcademicCommandType.STAR_GRADE;
+ } else if (commandModified.startsWith("star contact")) {
+ return AcademicCommandType.STAR_CONTACT;
+ } else if (commandModified.equals("list star")) {
+ return AcademicCommandType.LIST_STAR;
+ } else {
+ throw new InvalidCommandException();
+ }
+ }
+
+ /**
+ * Extract details of a contact from a string into a string array.
+ * @param command input string
+ * @return string array containing the various variables for the contact.
+ * @throws NumberFormatException when phone number inputted is not a valid phone number.
+ */
+ public static String[] getContact(String command) throws NumberFormatException, InvalidCommandException {
+
+ if (!command.contains("c/") | !command.contains("m/") | !command.contains("e/")) {
+ throw new InvalidCommandException();
+ }
+ String name = command.substring(command.indexOf("c/") + 2,
+ command.indexOf("m/")).trim();
+ String number = command.substring(command.indexOf("m/") + 2,
+ command.indexOf("e/")).trim();
+ String email = command.substring(command.indexOf("e/") + 2);
+ int numberAsInteger = Integer.parseInt(number);
+ if (numberAsInteger >= 100000000 || numberAsInteger <= 0) {
+ throw new NumberFormatException();
+ }
+
+ return new String[]{name, number, email};
+ }
+
+ /**
+ * Extract details of a module grade from a string into a string array.
+ * @param command input string
+ * @return string array containing the various variables for the module grade.
+ * @throws InvalidGradeException grade inputted is nto a valid grade.
+ * @throws InvalidMcException mc inputted is nto a valid mc.
+ */
+ public static String[] getGrade(String command)
+ throws InvalidGradeException, InvalidMcException, InvalidCommandException {
+
+ if (!command.contains("n/") | !command.contains("m/") | !command.contains("g/")) {
+ throw new InvalidCommandException();
+ }
+ String name = command.substring(command.indexOf("n/") + 2,
+ command.indexOf("m/")).trim();
+ String mc = command.substring(command.indexOf("m/") + 2,
+ command.indexOf("g/")).trim();
+ String grade = command.substring(command.indexOf("g/") + 2);
+
+ List list = Arrays.asList(Grade.listOfGrades);
+
+ if (!list.contains(grade.toLowerCase())) {
+ throw new InvalidGradeException();
+ } else if (Integer.parseInt(mc) <= 0) {
+ throw new InvalidMcException();
+ }
+ return new String[]{name, mc, grade};
+ }
+
+ /**
+ * Extracts details of a contact from the storage file into a string array.
+ * @param importedStatement input string from the storage file.
+ * @return string array containing the various variables for the contact.
+ */
+ public static String[] parseImportedPerson(String importedStatement) {
+ assert importedStatement.startsWith("[P]") : "Parsed statement should be a person";
+
+ int positionOfFirstDivider = importedStatement.indexOf("|");
+ int positionOfSecondDivider = importedStatement.indexOf("|",positionOfFirstDivider + 1);
+ int positionOfThirdDivider = importedStatement.indexOf("|",positionOfSecondDivider + 1);
+ int positionOfFourthDivider = importedStatement.lastIndexOf("|");
+
+ String var1 = importedStatement.substring(positionOfFirstDivider + 1,positionOfSecondDivider).trim();
+ String var2 = importedStatement.substring(positionOfSecondDivider + 1,positionOfThirdDivider).trim();
+ String var3 = importedStatement.substring(positionOfThirdDivider + 1, positionOfFourthDivider).trim();
+ String var4 = importedStatement.substring(positionOfFourthDivider + 1).trim();
+
+ return new String[]{var1, var2, var3, var4};
+
+ }
+
+ /**
+ * Extracts details of a module grade from the storage file into a string array.
+ * @param importedStatement input string from the storage file.
+ * @return string array containing the various variables for the module grade.
+ */
+ public static String[] parseImportedGrade(String importedStatement) {
+ assert importedStatement.startsWith("[G]") : "Parsed statement should be a grade";
+
+ int positionOfFirstDivider = importedStatement.indexOf("|");
+ int positionOfSecondDivider = importedStatement.indexOf("|",positionOfFirstDivider + 1);
+ int positionOfThirdDivider = importedStatement.indexOf("|", positionOfSecondDivider + 1);
+ int positionOfFourthDivider = importedStatement.indexOf("|", positionOfThirdDivider + 1);
+ int positionOfFifthDivider = importedStatement.lastIndexOf("|");
+
+
+ String var1 = importedStatement.substring(positionOfFirstDivider + 1,positionOfSecondDivider).trim();
+ String var2 = importedStatement.substring(positionOfSecondDivider + 1,positionOfThirdDivider).trim();
+ String var3 = importedStatement.substring(positionOfThirdDivider + 1,positionOfFourthDivider).trim();
+ String var4 = importedStatement.substring(positionOfFourthDivider + 1,positionOfFifthDivider).trim();
+ String var5 = importedStatement.substring(positionOfFifthDivider + 1).trim();
+
+ return new String[]{var1, var2, var3, var4, var5};
+
+ }
+
+ public static Integer parseDeletePerson(String command) {
+ return Integer.parseInt(command.substring("delete contact".length()).trim());
+ }
+
+ public static Integer parseDeleteGrade(String command) {
+ return Integer.parseInt(command.substring("delete grade".length()).trim());
+ }
+
+ public static Integer parseSuGrade(String command) {
+ return Integer.parseInt(command.substring("su grade".length()).trim());
+ }
+
+ public static Integer parseStarGrade(String command) {
+ return Integer.parseInt(command.substring("star grade".length()).trim());
+ }
+
+ public static Integer parseStarContact(String command) {
+ return Integer.parseInt(command.substring("star contact".length()).trim());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/academic/AcademicCommandType.java b/src/main/java/academic/AcademicCommandType.java
new file mode 100644
index 0000000000..4109302fe7
--- /dev/null
+++ b/src/main/java/academic/AcademicCommandType.java
@@ -0,0 +1,15 @@
+package academic;
+
+public enum AcademicCommandType {
+ ADD_CONTACT,
+ LIST_CONTACT,
+ ADD_GRADE,
+ CHECK_CAP,
+ LIST_GRADE,
+ DELETE_PERSON,
+ DELETE_GRADE,
+ SU_GRADE,
+ STAR_GRADE,
+ STAR_CONTACT,
+ LIST_STAR
+}
diff --git a/src/main/java/academic/AcademicRun.java b/src/main/java/academic/AcademicRun.java
new file mode 100644
index 0000000000..26806a4f2e
--- /dev/null
+++ b/src/main/java/academic/AcademicRun.java
@@ -0,0 +1,120 @@
+package academic;
+
+import exceptions.InvalidMcException;
+import exceptions.RepeatedGradeException;
+import exceptions.InvalidGradeException;
+import exceptions.InvalidCommandException;
+import exceptions.InvalidEmailException;
+import exceptions.EmptyInputException;
+
+import studyit.StudyItLog;
+import userinterface.ErrorMessage;
+import userinterface.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+//@@author luziyi9898
+/**
+ *Framework for the academic mode.
+ */
+public class AcademicRun {
+ /**
+ * list that stores the current list of grades.
+ */
+ private ArrayList currentGrades;
+
+ /**
+ * list that stores the current list of person.
+ */
+ private ArrayList listOfPerson;
+
+ /**
+ *Initializes the academic mode by initializing the array lists and loading the storage file.
+ */
+ public AcademicRun() {
+ currentGrades = new ArrayList<>();
+ listOfPerson = new ArrayList<>();
+
+ try {
+ AcademicStorage.loadFile(listOfPerson, currentGrades);
+ } catch (IOException e) {
+ System.out.println("Problem loading academic storage file");
+ StudyItLog.logger.warning("Problem loading academic storage file\n" + e);
+ }
+ StudyItLog.logger.info("Academic mode initialized");
+ }
+
+ /**
+ *Reads the user command and executes the various academic functions based on that command.
+ * @param command user input.
+ */
+ public void run(String command) {
+ try {
+ AcademicCommandType commandType = AcademicCommandParser.getAcademicCommandType(command);
+
+ if (commandType == AcademicCommandType.ADD_CONTACT) {
+ PersonBook.addPerson(AcademicCommandParser.getContact(command), listOfPerson);
+ Ui.printLine("Adding Contact");
+ } else if (commandType == AcademicCommandType.LIST_CONTACT) {
+ Ui.printLine(PersonBook.printPersonBook(listOfPerson));
+ } else if (commandType == AcademicCommandType.ADD_GRADE) {
+ GradeBook.addGrade(AcademicCommandParser.getGrade(command), currentGrades);
+ Ui.printLine("Adding Grade");
+ } else if (commandType == AcademicCommandType.CHECK_CAP) {
+ Ui.printLine(GradeBook.printCap(currentGrades));
+ } else if (commandType == AcademicCommandType.LIST_GRADE) {
+ Ui.printLine(GradeBook.printListOfGrades(currentGrades));
+ } else if (commandType == AcademicCommandType.DELETE_PERSON) {
+ PersonBook.deletePerson(AcademicCommandParser.parseDeletePerson(command),listOfPerson);
+ Ui.printLine("Deleting contact");
+ } else if (commandType == AcademicCommandType.DELETE_GRADE) {
+ GradeBook.deleteGrade(AcademicCommandParser.parseDeleteGrade(command),currentGrades);
+ Ui.printLine("Deleting grade");
+ } else if (commandType == AcademicCommandType.SU_GRADE) {
+ GradeBook.suGradeInGradeBook(AcademicCommandParser.parseSuGrade(command), currentGrades);
+ Ui.printLine("SU-ing grade");
+ } else if (commandType == AcademicCommandType.STAR_GRADE) {
+ GradeBook.starGrade(AcademicCommandParser.parseStarGrade(command), currentGrades);
+ Ui.printLine("Marking this grade as star");
+ } else if (commandType == AcademicCommandType.STAR_CONTACT) {
+ PersonBook.starContact(AcademicCommandParser.parseStarContact(command), listOfPerson);
+ Ui.printLine("Marking this person as star");
+ } else if (commandType == AcademicCommandType.LIST_STAR) {
+ AcademicUi.printStarList(currentGrades, listOfPerson);
+ }
+ } catch (InvalidCommandException e) {
+ ErrorMessage.printUnidentifiableCommand();
+ StudyItLog.logger.warning("Invalid academic command: Command unidentifiable");
+ } catch (StringIndexOutOfBoundsException e) {
+ ErrorMessage.printUnidentifiableInput();
+ StudyItLog.logger.warning("Invalid academic command: String Index out of bounds.");
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ ErrorMessage.printInvalidNumber();
+ StudyItLog.logger.warning("Invalid academic command: Invalid Number");
+ } catch (InvalidGradeException e) {
+ ErrorMessage.printInvalidGrade();
+ StudyItLog.logger.warning("Invalid academic command: Invalid Grade");
+ } catch (InvalidMcException e) {
+ ErrorMessage.printInvalidMc();
+ StudyItLog.logger.warning("Invalid academic command: Invalid MC");
+ } catch (InvalidEmailException e) {
+ ErrorMessage.printInvalidEmail();
+ StudyItLog.logger.warning("Invalid academic command: Invalid Email");
+ } catch (RepeatedGradeException e) {
+ ErrorMessage.printRepeatedGrade();
+ StudyItLog.logger.warning("Invalid academic command: Repeated Grade");
+ } catch (EmptyInputException e) {
+ ErrorMessage.printEmptyInput();
+ StudyItLog.logger.warning("Invalid academic command: Empty Input!");
+ }
+
+
+ try {
+ AcademicStorage.writeFile(listOfPerson, currentGrades);
+ } catch (IOException e) {
+ System.out.println("Problem writing to academic storage file");
+ StudyItLog.logger.warning("Problem writing to academic storage file\n" + e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/academic/AcademicStorage.java b/src/main/java/academic/AcademicStorage.java
new file mode 100644
index 0000000000..2ce63f52cc
--- /dev/null
+++ b/src/main/java/academic/AcademicStorage.java
@@ -0,0 +1,87 @@
+package academic;
+
+import exceptions.EmptyInputException;
+import exceptions.InvalidEmailException;
+import exceptions.RepeatedGradeException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ *Facilitates the storage of data on to a local storage file.
+ */
+public class AcademicStorage {
+ private static final String filePath = "data/academic.txt";
+
+ /**
+ * Determines the existence and validity of the stored file before running the loadText command.
+ * @param listOfPerson current list of person.
+ * @param listOfGrades current list of grade.
+ * @throws IOException when there is failed I/O operations.
+ */
+ public static void loadFile(ArrayList listOfPerson, ArrayList listOfGrades) throws IOException {
+ try {
+ loadText(listOfPerson, listOfGrades);
+ } catch (FileNotFoundException e) {
+ File f = new File(filePath);
+ f.createNewFile();
+ System.out.println("data/academic.txt is not found, creating a new file now!");
+ } catch (StringIndexOutOfBoundsException | NumberFormatException
+ | InvalidEmailException | RepeatedGradeException | EmptyInputException e) {
+ listOfGrades.clear();
+ listOfPerson.clear();
+ File f = new File(filePath);
+ f.createNewFile();
+ System.out.println("data/academic.txt is corrupted, your data will be reformatted.");
+ }
+ }
+
+ /**
+ * Reads the local storage file and update the array lists containing person and grades accordingly.
+ * @param listOfPerson current list of person.
+ * @param listOfGrades current list of grade.
+ * @throws FileNotFoundException when a local storage file is not found.
+ * @throws InvalidEmailException when email accepted is not a valid email
+ * @throws RepeatedGradeException when an existing grade is added repeatedly.
+ */
+ private static void loadText(ArrayList listOfPerson, ArrayList listOfGrades)
+ throws FileNotFoundException, InvalidEmailException, RepeatedGradeException, EmptyInputException {
+ File f = new File(filePath); // create a File for the given file path
+ Scanner s = new Scanner(f); // create a Scanner using the File as the source
+ while (s.hasNext()) {
+ String importedCommand = s.nextLine();
+ if (importedCommand.startsWith("[P]")) {
+ PersonBook.addPerson(AcademicCommandParser.parseImportedPerson(importedCommand),listOfPerson);
+ } else if (importedCommand.startsWith("[G]")) {
+ GradeBook.addGrade(AcademicCommandParser.parseImportedGrade(importedCommand),listOfGrades);
+ }
+ }
+ }
+
+ /**
+ * Updates the local storage file based on the array lists containing person and grades accordingly.
+ * @param listOfPerson current list of person.
+ * @param listOfGrades current list of grade.
+ * @throws IOException when there is failed I/O operations.
+ */
+ public static void writeFile(ArrayList listOfPerson, ArrayList listOfGrades)
+ throws IOException {
+
+ FileWriter fw = new FileWriter(filePath);
+
+ for (Person person : listOfPerson) {
+ if (person != null) {
+ fw.write(Person.printIndividualPerson(person) + System.lineSeparator());
+ }
+ }
+ for (Grade grade : listOfGrades) {
+ if (grade != null) {
+ fw.write(Grade.printIndividualGrade(grade) + System.lineSeparator());
+ }
+ }
+ fw.close();
+ }
+}
diff --git a/src/main/java/academic/AcademicUi.java b/src/main/java/academic/AcademicUi.java
new file mode 100644
index 0000000000..f3647ec284
--- /dev/null
+++ b/src/main/java/academic/AcademicUi.java
@@ -0,0 +1,45 @@
+package academic;
+
+import userinterface.Ui;
+import java.util.ArrayList;
+
+/**
+ * Text UI for academic mode.
+ */
+public class AcademicUi extends Ui {
+ public static void printStarList(ArrayList currentGrades, ArrayList listOfPerson) {
+ int listIndex = 1;
+ Boolean listIsEmpty = true;
+
+ System.out.println("Starred grades:");
+ for (Grade grade : currentGrades) {
+ if (grade.isStar) {
+ System.out.println(listIndex + "." + GradeBook.combineGradeDetails(grade));
+ listIsEmpty = false;
+ listIndex++;
+ }
+ }
+ printEmpty(listIsEmpty);
+
+ // Reset the boolean flag
+ listIsEmpty = true;
+
+ System.out.println("\nStarred contacts:");
+ listIndex = 1;
+ for (Person person : listOfPerson) {
+ if (person.isStar) {
+ System.out.println(listIndex + "." + PersonBook.combinePersonDetails(person));
+ listIsEmpty = false;
+ listIndex++;
+ }
+ }
+ printEmpty(listIsEmpty);
+ printDivider();
+ }
+
+ public static void printEmpty(Boolean isEmpty) {
+ if (isEmpty) {
+ System.out.println("");
+ }
+ }
+}
diff --git a/src/main/java/academic/Grade.java b/src/main/java/academic/Grade.java
new file mode 100644
index 0000000000..2c6b129068
--- /dev/null
+++ b/src/main/java/academic/Grade.java
@@ -0,0 +1,96 @@
+package academic;
+
+/**
+ * Represents a grade for a module in study it.
+ */
+public class Grade {
+ protected String moduleName;
+ protected Integer moduleCredits;
+ protected String moduleGrade;
+ protected Boolean isModuleSued;
+ protected Boolean isStar;
+
+ /**
+ * List of valid grades the program accepts.
+ */
+ public static String[] listOfGrades = new String[]{"a+","a","a-","b+","b","b-","c+","c","d+","d","f"};
+
+
+ public Grade(String name, Integer credits, String grade) {
+ this.moduleName = name;
+ this.moduleCredits = credits;
+ this.moduleGrade = grade;
+ this.isModuleSued = false;
+ this.isStar = false;
+ }
+
+ /**
+ * Receive a grade and convert it into a string to be stored into local storage.
+ * @param grade grade to be stored.
+ * @return string to be added to local storage.
+ */
+ public static String printIndividualGrade(Grade grade) {
+ return "[G] | " + grade.moduleName + " | " + grade.moduleCredits
+ + " | " + grade.moduleGrade + " | " + grade.isModuleSued
+ + " | " + grade.isStar;
+ }
+
+ public static Integer getModuleCredits(Grade grade) {
+ return grade.moduleCredits;
+ }
+
+ public static String getModuleGrade(Grade grade) {
+ return grade.moduleGrade;
+ }
+
+ public static void suGrade(Grade grade) {
+ grade.isModuleSued = true;
+ }
+
+ public static Boolean isGradeSued(Grade grade) {
+ return grade.isModuleSued;
+ }
+
+ public static void changeStarGrade(Grade grade) {
+ grade.isStar = true;
+ }
+
+ public static Boolean isGradeStar(Grade grade) {
+ return grade.isStar;
+ }
+
+ /**
+ * converts grade of module into its corresponding score.
+ * @param input letter representing grade.
+ * @return marks to be used for CAP caculation.
+ */
+ public static double convertLetterToCredit(String input) {
+ switch (input.trim().toLowerCase()) {
+ case "a+":
+ case "a":
+ return 5.0;
+ case "a-":
+ return 4.5;
+ case "b+":
+ return 4.0;
+ case "b":
+ return 3.5;
+ case "b-":
+ return 3.0;
+ case "c+":
+ return 2.5;
+ case "c":
+ return 2.0;
+ case "d+":
+ return 1.5;
+ case "d":
+ return 1.0;
+ case "f":
+ return 0;
+ default:
+ return 0;
+ }
+
+ }
+
+}
diff --git a/src/main/java/academic/GradeBook.java b/src/main/java/academic/GradeBook.java
new file mode 100644
index 0000000000..f557cc51ca
--- /dev/null
+++ b/src/main/java/academic/GradeBook.java
@@ -0,0 +1,122 @@
+package academic;
+
+import exceptions.EmptyInputException;
+import exceptions.RepeatedGradeException;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a grade book in study-it.
+ */
+public class GradeBook {
+
+ /**
+ * Adds a grade to an array list of grades.
+ * @param args parameters of the grade.
+ * @param currentGrades array list of grade.
+ * @throws RepeatedGradeException when grade added is already present in list of grade.
+ */
+ public static void addGrade(String[] args, ArrayList currentGrades)
+ throws RepeatedGradeException, EmptyInputException {
+
+ for (Grade grade : currentGrades) {
+
+ if (args[0].equals("")) {
+ throw new EmptyInputException();
+ } else if (args[0].equals(grade.moduleName)) {
+ throw new RepeatedGradeException();
+ }
+ }
+ currentGrades.add(new Grade(args[0], Integer.parseInt(args[1]), args[2].toUpperCase()));
+ if (args.length == 5) {
+ if (args[3].equals("true")) {
+ Grade.suGrade(currentGrades.get(currentGrades.size() - 1));
+ }
+ if (args[4].equals("true")) {
+ Grade.changeStarGrade(currentGrades.get(currentGrades.size() - 1));
+ }
+ }
+ }
+
+ /**
+ * Delete a grade from an array list of grades.
+ * @param indexToBeDeleted index of the grade to be deleted.
+ * @param currentGrades array list of grade.
+ */
+ public static void deleteGrade(Integer indexToBeDeleted, ArrayList currentGrades) {
+ currentGrades.remove(indexToBeDeleted - 1);
+ }
+
+ /**
+ * Calculate current CAP and return it as a string.
+ * @param currentGrades array list of grade.
+ * @return string with current CAP.
+ */
+ public static String printCap(ArrayList currentGrades) {
+ double totalGradeScore = 0;
+ int totalCredits = 0;
+ for (Grade grade : currentGrades) {
+ if (!Grade.isGradeSued(grade)) {
+ totalCredits += Grade.getModuleCredits(grade);
+ totalGradeScore += Grade.convertLetterToCredit(Grade.getModuleGrade(grade))
+ * Grade.getModuleCredits(grade);
+ }
+ }
+ if (totalCredits != 0) {
+ return "Current CAP is " + totalGradeScore / totalCredits + ".";
+ } else {
+ return "Current CAP is not available!";
+ }
+ }
+
+ /**
+ * SU a grade.
+ * @param indexToBeSued index of the grade to be SUed.
+ * @param currentGrades array list of grade.
+ */
+ public static void suGradeInGradeBook(Integer indexToBeSued, ArrayList currentGrades) {
+ Grade.suGrade(currentGrades.get(indexToBeSued - 1));
+ }
+
+ public static void starGrade(Integer indexToBeStar, ArrayList currentGrades) {
+ if (indexToBeStar > 0 && indexToBeStar <= currentGrades.size()) {
+ Grade.changeStarGrade(currentGrades.get(indexToBeStar - 1));
+ } else {
+ throw new NumberFormatException();
+ }
+ }
+
+ public static String printListOfGrades(ArrayList currentGrades) {
+ int listIndex = 0;
+ StringBuilder listToPrint = new StringBuilder();
+ if (currentGrades.size() == 0) {
+ listToPrint.append("You have not added any grades!");
+ }
+ for (Grade grade : currentGrades) {
+ if (grade != null) {
+ listToPrint.append(listIndex + 1 + ".");
+ listToPrint.append(combineGradeDetails(grade));
+ listIndex++;
+ if (currentGrades.size() != listIndex) {
+ listToPrint.append("\n");
+ }
+ }
+ }
+ return listToPrint.toString();
+ }
+
+ public static String combineGradeDetails(Grade grade) {
+ StringBuilder gradeDetail = new StringBuilder();
+
+ gradeDetail.append("[" + grade.moduleName + "]");
+ gradeDetail.append(" [" + grade.moduleCredits + "MC]");
+ gradeDetail.append(" [" + grade.moduleGrade + "]");
+ if (Grade.isGradeSued(grade)) {
+ gradeDetail.append(" (This mod is SU-ed)");
+ }
+ if (Grade.isGradeStar(grade)) {
+ gradeDetail.append(" (*)");
+ }
+ return gradeDetail.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/academic/Person.java b/src/main/java/academic/Person.java
new file mode 100644
index 0000000000..2c3fc0aaf8
--- /dev/null
+++ b/src/main/java/academic/Person.java
@@ -0,0 +1,36 @@
+package academic;
+
+/**
+ * Represents a person in study-it.
+ */
+public class Person {
+ protected String nameOfPerson;
+ protected String contactNumberOfPerson;
+ protected String emailOfPerson;
+ protected Boolean isStar;
+
+ public Person(String name, String number, String email) {
+ this.nameOfPerson = name;
+ this.contactNumberOfPerson = number;
+ this.emailOfPerson = email;
+ this.isStar = false;
+ }
+
+ /**
+ * Receive a person and convert it into a string to be stored into local storage.
+ * @param person person to be stored.
+ * @return string to be added to local storage.
+ */
+ public static String printIndividualPerson(Person person) {
+ return "[P] | " + person.nameOfPerson + " | " + person.contactNumberOfPerson
+ + " | " + person.emailOfPerson + " | " + person.isStar;
+ }
+
+ public static void changePersonStar(Person person) {
+ person.isStar = true;
+ }
+
+ public static Boolean isStar(Person person) {
+ return person.isStar;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/academic/PersonBook.java b/src/main/java/academic/PersonBook.java
new file mode 100644
index 0000000000..946bc7fc27
--- /dev/null
+++ b/src/main/java/academic/PersonBook.java
@@ -0,0 +1,85 @@
+package academic;
+
+import exceptions.EmptyInputException;
+import exceptions.InvalidEmailException;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a grade book in study-it.
+ */
+public class PersonBook {
+ /**
+ * Adds a person to an array list of person.
+ * @param args parameters of the person.
+ * @param listOfPerson array list of person.
+ * @throws InvalidEmailException when email added does not have an @ in it.
+ */
+ public static void addPerson(String[] args, ArrayList listOfPerson)
+ throws InvalidEmailException, EmptyInputException {
+
+ if (args[0].equals("")) {
+ throw new EmptyInputException();
+ }
+
+ if (args[2].contains("@")) {
+ listOfPerson.add(new Person(args[0], args[1], args[2]));
+ if (args.length == 4) {
+ if (args[3].equals("true")) {
+ Person.changePersonStar(listOfPerson.get(listOfPerson.size() - 1));
+ }
+ }
+ } else {
+ throw new InvalidEmailException();
+ }
+ }
+
+ /**
+ * Delete a person from an array list of person.
+ * @param indexToBeDeleted index of the person to be deleted.
+ * @param listOfPerson array list of person.
+ */
+ public static void deletePerson(Integer indexToBeDeleted, ArrayList listOfPerson) {
+ listOfPerson.remove(indexToBeDeleted - 1);
+ }
+
+ public static void starContact(Integer indexToBeStar, ArrayList listOfPerson) {
+ if (indexToBeStar > 0 && indexToBeStar <= listOfPerson.size()) {
+ Person.changePersonStar(listOfPerson.get(indexToBeStar - 1));
+ } else {
+ throw new NumberFormatException();
+ }
+ }
+
+ public static String printPersonBook(ArrayList listOfPerson) {
+ int listIndex = 0;
+ StringBuilder listToPrint = new StringBuilder();
+ if (listOfPerson.size() == 0) {
+ listToPrint.append("You have not added any contacts!");
+ }
+ for (Person person : listOfPerson) {
+ if (person != null) {
+ listToPrint.append((listIndex + 1) + ".");
+ listToPrint.append(combinePersonDetails(person));
+ listIndex++;
+ if (listOfPerson.size() != listIndex) {
+ listToPrint.append("\n");
+ }
+ }
+ }
+
+ return listToPrint.toString();
+ }
+
+ public static String combinePersonDetails(Person person) {
+ StringBuilder personDetails = new StringBuilder();
+
+ personDetails.append("[" + person.nameOfPerson + "]");
+ personDetails.append(" [" + person.contactNumberOfPerson + "]");
+ personDetails.append(" [" + person.emailOfPerson + "]");
+ if (Person.isStar(person)) {
+ personDetails.append(" (*)");
+ }
+ return personDetails.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/bookmark/BookmarkCategory.java b/src/main/java/bookmark/BookmarkCategory.java
new file mode 100644
index 0000000000..54dbdaeba2
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkCategory.java
@@ -0,0 +1,32 @@
+package bookmark;
+
+import java.util.ArrayList;
+
+public class BookmarkCategory {
+ private String name;
+ private ArrayList links = new ArrayList<>();
+
+ public BookmarkCategory(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ArrayList getLinks() {
+ return links;
+ }
+
+ public void addLink(String link, String title) {
+ links.add(new BookmarkList(link, title));
+ }
+
+ public void removeLink(int number) {
+ links.remove(number - 1);
+ }
+
+ public void markLinkAsStar(int number) {
+ links.get(number).markLinkAsStar();
+ }
+}
diff --git a/src/main/java/bookmark/BookmarkList.java b/src/main/java/bookmark/BookmarkList.java
new file mode 100644
index 0000000000..f447f073c1
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkList.java
@@ -0,0 +1,53 @@
+package bookmark;
+
+public class BookmarkList {
+ private String link;
+ private Boolean star;
+ private String title;
+
+ public BookmarkList(String link, String title) {
+ this.link = link;
+ this.star = false;
+ this.title = title;
+ }
+
+ public String getPrintLink() {
+ String returnLink = "";
+ if (star) {
+ returnLink += "|STAR|";
+ }
+ if (title != null) {
+ return returnLink + link + " t->" + title;
+ } else {
+ return returnLink + link;
+ }
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void markLinkAsStar() {
+ if (!this.star) {
+ this.star = true;
+ } else {
+ assert this.star : "star is unmarked incorrectly";
+ this.star = false;
+ }
+ }
+
+ private String getStarIcon() {
+ return (star ? " (*)" : ""); //return tick symbols
+ }
+
+ public String toString() {
+ if (title == "" || title == null) {
+ return link + getStarIcon();
+ }
+ return title + ": " + link + getStarIcon();
+ }
+
+ public Boolean getStar() {
+ return star;
+ }
+}
diff --git a/src/main/java/bookmark/BookmarkParser.java b/src/main/java/bookmark/BookmarkParser.java
new file mode 100644
index 0000000000..60f68560d2
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkParser.java
@@ -0,0 +1,47 @@
+package bookmark;
+
+import bookmark.commands.AddCategoryCommand;
+import bookmark.commands.AddLinkCommand;
+import bookmark.commands.BackCommand;
+import bookmark.commands.ChangeModeCommand;
+import bookmark.commands.BookmarkCommand;
+import bookmark.commands.ListCommand;
+import bookmark.commands.RemoveCategoryCommand;
+import bookmark.commands.RemoveLinkCommand;
+import bookmark.commands.StarCommand;
+import exceptions.InvalidCommandException;
+import studyit.CommandParser;
+import studyit.StudyItLog;
+
+public class BookmarkParser extends CommandParser {
+ public BookmarkParser() {
+ }
+
+ public BookmarkCommand evaluateInput(String command, int chosenCategory) throws InvalidCommandException {
+ if (command == null) {
+ StudyItLog.logger.finest("Empty command");
+ throw new InvalidCommandException();
+ }
+ String commandModified = command.trim().toLowerCase();
+ if (commandModified.startsWith("bm")) {
+ return new ChangeModeCommand(command, chosenCategory);
+ } else if (commandModified.startsWith("add")) {
+ return new AddLinkCommand(command, chosenCategory);
+ } else if (commandModified.startsWith("rm")) {
+ return new RemoveLinkCommand(command, chosenCategory);
+ } else if (commandModified.startsWith("list")) {
+ return new ListCommand(command,chosenCategory);
+ } else if (commandModified.startsWith("back")) {
+ return new BackCommand(command,chosenCategory);
+ } else if (commandModified.startsWith("cat")) {
+ return new AddCategoryCommand(command,chosenCategory);
+ } else if (commandModified.startsWith("delete")) {
+ return new RemoveCategoryCommand(command,chosenCategory);
+ } else if (commandModified.startsWith("star")) {
+ return new StarCommand(command,chosenCategory);
+ } else {
+ StudyItLog.logger.info("Cannot understand bookmark command");
+ throw new InvalidCommandException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/bookmark/BookmarkRun.java b/src/main/java/bookmark/BookmarkRun.java
new file mode 100644
index 0000000000..1d838be732
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkRun.java
@@ -0,0 +1,41 @@
+package bookmark;
+
+import bookmark.commands.BookmarkCommand;
+import exceptions.InvalidCommandException;
+import studyit.StudyItLog;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class BookmarkRun {
+ private ArrayList bookmarkCategories;
+ private BookmarkUi bookmarkUi;
+ private BookmarkParser bookmarkParser;
+ private BookmarkStorage bookmarkStorage;
+ private int mode = 0;
+
+ public BookmarkRun() {
+ bookmarkUi = new BookmarkUi();
+ bookmarkParser = new BookmarkParser();
+ bookmarkStorage = new BookmarkStorage("data/bookmark.txt");
+ try {
+ bookmarkCategories = bookmarkStorage.loadFile();
+ } catch (IOException e) {
+ System.out.println("An error occured: " + e.getMessage());
+ }
+
+ StudyItLog.logger.info("Bookmark mode initialized");
+ }
+
+ public void run(String command) {
+ try {
+ BookmarkCommand c = bookmarkParser.evaluateInput(command,mode);
+ c.executeCommand(bookmarkUi,bookmarkCategories,bookmarkStorage);
+ mode = c.getCategoryNumber();
+ } catch (InvalidCommandException e) {
+ bookmarkUi.showInvalidError("Bookmark Command");
+ StudyItLog.logger.warning("Invalid bookmark command: Command unidentifiable");
+ }
+ }
+}
diff --git a/src/main/java/bookmark/BookmarkStorage.java b/src/main/java/bookmark/BookmarkStorage.java
new file mode 100644
index 0000000000..b1a29ab0c6
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkStorage.java
@@ -0,0 +1,101 @@
+package bookmark;
+
+import studyit.StudyItLog;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+
+public class BookmarkStorage {
+ private final File bookmarkFile;
+ private final String filePath;
+
+ public BookmarkStorage(String filePath) {
+ String dirPath = "data";
+ File fileDir = new File(dirPath);
+
+ if (!fileDir.exists()) {
+ fileDir.mkdir();
+ }
+
+ this.filePath = filePath;
+ bookmarkFile = new File(filePath);
+ }
+
+ public ArrayList loadFile() throws IOException {
+ try {
+ Scanner s = new Scanner(bookmarkFile);
+ ArrayList bookmarkCategories = new ArrayList<>();
+ int i = 0;
+ while (s.hasNext()) {
+ String[] parseCategory = s.nextLine().split(" = ");
+ String categoryName = parseCategory[0];
+ bookmarkCategories.add(new BookmarkCategory(categoryName));
+ if (parseCategory.length < 2) {
+ i++;
+ continue;
+ }
+ String[] links = parseCategory[1].split(" \\| ");
+ String title;
+ int x = 0;
+ for (String link : links) {
+ link = link.trim();
+ if (link.contains(" t->")) {
+ String[] array = link.split(" t->");
+ link = array[0].trim();
+ title = array[1].trim();
+ } else {
+ title = null;
+ }
+ assert i >= 0 : "Problem reading file";
+ if (link.contains("|STAR|")) {
+ bookmarkCategories.get(i).addLink(link.substring(6),title);
+ bookmarkCategories.get(i).markLinkAsStar(x);
+ } else {
+ bookmarkCategories.get(i).addLink(link,title);
+ }
+ x++;
+ }
+ i++;
+ }
+ return bookmarkCategories;
+ } catch (FileNotFoundException e) {
+ System.out.println("data/bookmark.txt is not found, creating a new file now!");
+ bookmarkFile.createNewFile();
+ ArrayList newBookmarkCategories = new ArrayList<>();
+ newBookmarkCategories.add(new BookmarkCategory("NUS"));
+ newBookmarkCategories.add(new BookmarkCategory("Zoom"));
+ newBookmarkCategories.add(new BookmarkCategory("Internship"));
+ newBookmarkCategories.add(new BookmarkCategory("Hackathon"));
+ newBookmarkCategories.add(new BookmarkCategory("Career Talk"));
+ saveLinksToFile(newBookmarkCategories);
+ StudyItLog.logger.info(e + "\nflashcard storage file created");
+ return newBookmarkCategories;
+ }
+ }
+
+ public void saveLinksToFile(ArrayList categories) {
+ try {
+ FileWriter fw = new FileWriter(filePath, false); //true append, false overwrite
+ for (BookmarkCategory category : categories) {
+ fw.write(category.getName() + " = " + getCategoryLinks(category) + System.lineSeparator());
+ }
+ fw.close();
+ } catch (IOException e) {
+ System.out.println("Something went wrong" + e.getMessage());
+ StudyItLog.logger.warning("Problem writing to bookmark storage file\n" + e);
+ }
+ }
+
+ private String getCategoryLinks(BookmarkCategory category) {
+ String listOfLinks = "";
+ for (BookmarkList link : category.getLinks()) {
+ listOfLinks += link.getPrintLink() + " | ";
+ }
+ return listOfLinks;
+ }
+}
diff --git a/src/main/java/bookmark/BookmarkUi.java b/src/main/java/bookmark/BookmarkUi.java
new file mode 100644
index 0000000000..c15b575eea
--- /dev/null
+++ b/src/main/java/bookmark/BookmarkUi.java
@@ -0,0 +1,125 @@
+package bookmark;
+
+import java.util.ArrayList;
+
+public class BookmarkUi {
+
+ public BookmarkUi() {
+
+ }
+
+ public static void printWelcomeBookmarkMessage() {
+ System.out.println("Welcome to bookmark mode!");
+ System.out.println("You can use this mode to bookmark your links for easier access!");
+ System.out.println("View your list of links by typing \"list\"");
+ System.out.println("\nChoose your category by typing \"bm !\"");
+ System.out.println("\nView your category available by typing \"list -c\"");
+ System.out.println("Otherwise, insert \"help\" to find the list of commands available.");
+ }
+
+ public void showBookmarkCategoryList(ArrayList bookmarkCategories) {
+ System.out.println("Here are the categories available:");
+ int i = 1;
+ for (BookmarkCategory category: bookmarkCategories) {
+ System.out.println(i + "." + category.getName());
+ i++;
+ }
+ }
+
+ public void showBookmarkLinkList(BookmarkCategory category) {
+ System.out.println("Bookmarks in " + category.getName() + ": ");
+ if (category.getLinks().size() == 0) {
+ System.out.println("\t");
+ } else {
+ int i = 1;
+ for (BookmarkList link: category.getLinks()) {
+ System.out.println("\t" + i + "." + link);
+ i++;
+ }
+ }
+ }
+
+ public void printGoodbyeMessage() {
+ showCurrentMode("Bookmark Main");
+ System.out.println("Use \"exit\" to exit the mode or enter another category\n"
+ + "using \"bm \".");
+ }
+
+ public void showBookmarkList(ArrayList categories) {
+ System.out.println("Here is the entire list");
+ for (int i = 0; i < categories.size(); i++) {
+ System.out.println((i + 1) + ". Category: " + categories.get(i).getName());
+ showBookmarkLinkList(categories.get(i));
+ }
+ if (categories.size() == 0) {
+ System.out.println("\t");
+ }
+ }
+
+ public void printChooseCategoryMessage() {
+ System.out.println("You have not chosen a category.");
+ System.out.println("Change category by using \"bm \". ");
+ System.out.println("View the categories available by using \"list -c\". ");
+ }
+
+ public void showEmptyError(String item) {
+ System.out.println("Empty " + item + " :(");
+ System.out.println("Please input a " + item);
+ System.out.println("You can input \"help\" to view the input format.");
+ }
+
+ public void showInvalidError(String item) {
+ System.out.println("Sorry you have entered an invalid " + item
+ + " or your input is in the wrong format!");
+ System.out.println("Please enter a valid " + item + " or input \"help\" to find out the correct format!");
+ }
+
+ public void showInvalidNumberError() {
+ System.out.println("Sorry, the format requires a valid number.");
+ System.out.println("Please enter a valid number!");
+ System.out.println("You can input \"help\" to view the input format.");
+ }
+
+ public void showModeChangeMessage(ArrayList categories, int categoryNumberInList) {
+ System.out.println("You are now in " + categories.get(categoryNumberInList).getName() + " category");
+ showBookmarkLinkList(categories.get(categoryNumberInList));
+ System.out.println("Add new bookmarks by using \"add \"");
+ }
+
+ public void showAlreadyInModeMessage(ArrayList categories, int categoryName) {
+ System.out.println("You are already in chosen Category: " + categories.get(categoryName - 1).getName());
+ showBookmarkLinkList(categories.get(categoryName - 1));
+ }
+
+ public void showStarBookmarks(ArrayList categories) {
+ int i = 0;
+ System.out.println("Starred bookmarks: ");
+ for (BookmarkCategory category : categories) {
+ for (BookmarkList link : category.getLinks()) {
+ if (link.getStar()) {
+ i++;
+ System.out.println(i + "." + link);
+ }
+ }
+ }
+ if (i == 0) {
+ System.out.println("");
+ }
+
+ }
+
+ public void showExistingBookmarkError(String item) {
+ System.out.println("You have the exact same bookmark " + item + " in your list!");
+ System.out.println("Add a new unique bookmark " + item + "!");
+ }
+
+ public void showCorrectCommand(String item) {
+ System.out.println("Did you mean \"" + item + "\"?");
+ System.out.println("If you did please input \"" + item + "\"");
+ System.out.println("If not input \"help\" to view the correct command format.");
+ }
+
+ public void showCurrentMode(String name) {
+ System.out.println("You are currently in : " + name);
+ }
+}
diff --git a/src/main/java/bookmark/commands/AddCategoryCommand.java b/src/main/java/bookmark/commands/AddCategoryCommand.java
new file mode 100644
index 0000000000..90bac8613c
--- /dev/null
+++ b/src/main/java/bookmark/commands/AddCategoryCommand.java
@@ -0,0 +1,68 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.EmptyBookmarkException;
+import exceptions.ExistingBookmarkException;
+
+import java.util.ArrayList;
+
+public class AddCategoryCommand extends BookmarkCommand {
+ public static final int CAT_LENGTH = 3;
+ private int categoryNumber;
+ private String categoryToAdd;
+ private String categoryName;
+
+ public AddCategoryCommand(String command,int categoryNumber) {
+ this.categoryNumber = categoryNumber;
+ this.categoryToAdd = command.trim();
+ assert command.toLowerCase().startsWith("cat") : "Add category command is "
+ + "called when line does not start with cat";
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Adds new BookmarkCategory to ArrayList after evaluating category name.
+ *
+ * @param ui prints output message
+ * @param categories add category to array list
+ * @param storage store new category to file
+ * @throws EmptyBookmarkException if category name is empty
+ * @throws ExistingBookmarkException if bookmark category already exist
+ */
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage storage) {
+ try {
+ evaluateCategory();
+ checkCategory(categories);
+ categories.add(new BookmarkCategory(categoryName));
+ System.out.println("Adding " + categoryName + " to bookmark category...");
+ ui.showBookmarkCategoryList(categories);
+ storage.saveLinksToFile(categories);
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Category");
+ } catch (ExistingBookmarkException e) {
+ ui.showExistingBookmarkError("category");
+ }
+ }
+
+ private void evaluateCategory() throws EmptyBookmarkException {
+ if (categoryToAdd.length() <= CAT_LENGTH) {
+ throw new EmptyBookmarkException();
+ }
+ assert categoryToAdd.length() > 0 : "Link should not be empty";
+ categoryName = categoryToAdd.substring(CAT_LENGTH).trim();
+ }
+
+ private void checkCategory(ArrayList categories) throws ExistingBookmarkException {
+ for (BookmarkCategory existingCategory : categories) {
+ if (categoryName.toLowerCase().equals(existingCategory.getName().toLowerCase())) {
+ throw new ExistingBookmarkException();
+ }
+ }
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+}
diff --git a/src/main/java/bookmark/commands/AddLinkCommand.java b/src/main/java/bookmark/commands/AddLinkCommand.java
new file mode 100644
index 0000000000..47376b5e7d
--- /dev/null
+++ b/src/main/java/bookmark/commands/AddLinkCommand.java
@@ -0,0 +1,91 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkList;
+import bookmark.BookmarkUi;
+import exceptions.ExistingBookmarkException;
+import exceptions.InvalidBookmarkException;
+import exceptions.EmptyBookmarkException;
+
+import java.util.ArrayList;
+
+public class AddLinkCommand extends BookmarkCommand {
+ public static final int ADD_LENGTH = 3;
+ private String line;
+ private int categoryNumber;
+ private String link;
+ private String title;
+
+ public AddLinkCommand(String line, int categoryNumber) {
+ this.categoryNumber = categoryNumber;
+ this.line = line.trim();
+ assert line.toLowerCase().startsWith("add") : "Add link command is called when line does not start with add";
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Adds new BookmarkLink to ArrayList after evaluating category link.
+ *
+ * @param ui prints output message
+ * @param categories add link to array list
+ * @param storage store new link to file
+ * @throws EmptyBookmarkException if category name is empty
+ * @throws ExistingBookmarkException if bookmark category already exist
+ * @throws InvalidBookmarkException if bookmark link is invalid.
+ */
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage storage) {
+ try {
+ if (categoryNumber == 0) {
+ ui.printChooseCategoryMessage();
+ } else {
+ assert categoryNumber > 0 : "Category number is not chosen";
+ evaluateLink();
+ checkLink(categories);
+ categories.get(categoryNumber - 1).addLink(link,title);
+ ui.showBookmarkLinkList(categories.get(categoryNumber - 1));
+ storage.saveLinksToFile(categories);
+ }
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Link / title");
+ } catch (InvalidBookmarkException e) {
+ ui.showInvalidError("Link");
+ } catch (ExistingBookmarkException e) {
+ ui.showExistingBookmarkError("link");
+ }
+ }
+
+ private void evaluateLink() throws EmptyBookmarkException, InvalidBookmarkException {
+ if (line.length() <= ADD_LENGTH) {
+ throw new EmptyBookmarkException();
+ }
+ assert line.length() > 0 : "Link should not be empty";
+ link = line.substring(ADD_LENGTH).trim();
+ if (link.contains(" t->")) {
+ String[] array = link.split(" t->");
+ if (array.length < 2) {
+ throw new EmptyBookmarkException();
+ }
+ link = array[0].trim();
+ title = array[1].trim();
+ } else {
+ title = null;
+ }
+ if (!link.contains(".") || link.contains(" ") || link.contains("|")) {
+ throw new InvalidBookmarkException();
+ }
+ assert link.contains(".") && !link.contains(" ") : "Invalid link";
+ }
+
+ private void checkLink(ArrayList categories) throws ExistingBookmarkException {
+ for (BookmarkList existingLink : categories.get(categoryNumber - 1).getLinks()) {
+ if (link.equals(existingLink.getLink())) {
+ throw new ExistingBookmarkException();
+ }
+ }
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+}
diff --git a/src/main/java/bookmark/commands/BackCommand.java b/src/main/java/bookmark/commands/BackCommand.java
new file mode 100644
index 0000000000..f1b51f98a8
--- /dev/null
+++ b/src/main/java/bookmark/commands/BackCommand.java
@@ -0,0 +1,48 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.EmptyBookmarkException;
+import exceptions.ExistingBookmarkException;
+import exceptions.InvalidBookmarkException;
+
+import java.util.ArrayList;
+
+public class BackCommand extends BookmarkCommand {
+ public static final int BACK_LENGTH = 4;
+ private int categoryNumber;
+ private String input;
+
+ public BackCommand(String command, int chosenCategory) {
+ this.input = command.trim();
+ this.categoryNumber = chosenCategory;
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Goes back to the previous mode vy changing category number.
+ *
+ * @param ui prints output message
+ * @param categories prints category list
+ */
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage bookmarkStorage) {
+ if (input.substring(BACK_LENGTH).length() > 0) {
+ ui.showCorrectCommand("back");
+ } else {
+ if (categoryNumber == 0) {
+ ui.printGoodbyeMessage();
+ } else {
+ ui.showCurrentMode("Bookmark Main");
+ ui.showBookmarkCategoryList(categories);
+ assert categoryNumber > 0 : "Category number more than 0";
+ categoryNumber = 0;
+ }
+ }
+
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/bookmark/commands/BookmarkCommand.java b/src/main/java/bookmark/commands/BookmarkCommand.java
new file mode 100644
index 0000000000..2beaf5c504
--- /dev/null
+++ b/src/main/java/bookmark/commands/BookmarkCommand.java
@@ -0,0 +1,15 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+
+
+import java.util.ArrayList;
+
+public abstract class BookmarkCommand {
+ public abstract void executeCommand(BookmarkUi ui, ArrayList categories,
+ BookmarkStorage bookmarkStorage);
+
+ public abstract int getCategoryNumber();
+}
diff --git a/src/main/java/bookmark/commands/ChangeModeCommand.java b/src/main/java/bookmark/commands/ChangeModeCommand.java
new file mode 100644
index 0000000000..85f8530343
--- /dev/null
+++ b/src/main/java/bookmark/commands/ChangeModeCommand.java
@@ -0,0 +1,68 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.ExistingBookmarkException;
+import exceptions.InvalidBookmarkException;
+import exceptions.EmptyBookmarkException;
+
+import java.util.ArrayList;
+
+public class ChangeModeCommand extends BookmarkCommand {
+ private String line;
+ public static final int RM_LENGTH = 2;
+ private int categoryNumber;
+
+ public ChangeModeCommand(String line, int categoryNumber) {
+ this.line = line.trim();
+ this.categoryNumber = categoryNumber;
+ assert line.startsWith("bm") : "change mode command is called when line does not start with cd";
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Change mode from bookmark main to each bookmark category.
+ *
+ * @param ui prints output message.
+ * @param categories prints list of links in category chosen.
+ */
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage bookmarkStorage) {
+ try {
+ int category = getChosenCategory(categories);
+ if (category == categoryNumber) {
+ ui.showAlreadyInModeMessage(categories,categoryNumber);
+ assert category == categoryNumber : "studyit.Mode does not change when it is already in the mode";
+ } else {
+ categoryNumber = category;
+ int categoryNumberInList = categoryNumber - 1;
+ ui.showModeChangeMessage(categories, categoryNumberInList);
+ assert category > 0 : "Category number incorrect";
+ }
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Category Number");
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ ui.showInvalidNumberError();
+ } catch (InvalidBookmarkException e) {
+ ui.showInvalidError("Category Number");
+ }
+ }
+
+ private int getChosenCategory(ArrayList categories)
+ throws InvalidBookmarkException, EmptyBookmarkException, NumberFormatException {
+ if (line.length() <= RM_LENGTH) {
+ throw new EmptyBookmarkException();
+ }
+ int category = Integer.parseInt(line.substring(RM_LENGTH).trim());
+ if (category == 0 || category > categories.size()) {
+ throw new InvalidBookmarkException();
+ }
+ return category;
+
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/bookmark/commands/ListCommand.java b/src/main/java/bookmark/commands/ListCommand.java
new file mode 100644
index 0000000000..0fc6a5809f
--- /dev/null
+++ b/src/main/java/bookmark/commands/ListCommand.java
@@ -0,0 +1,99 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+
+import java.util.ArrayList;
+
+public class ListCommand extends BookmarkCommand {
+ public static final int LIST_LENGTH = 4;
+ public static final int STAR_LENGTH = 4;
+ public static final int CAT_LENGTH = 3;
+ private int categoryNumber;
+ private String input;
+
+ public ListCommand(String command, int categoryNumber) {
+ this.input = command.trim();
+ this.categoryNumber = categoryNumber;
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Shows user the list of bookmarks according to the variations of list command.
+ * list -a : shows all the bookmark links in every category.
+ * list: shows the bookmark links in the category the user is in.
+ * list -s : shows all the starred bookmark links
+ * list -c : shows the list of categories available
+ *
+ * @param ui prints output message
+ * @param categories prints category list
+ */
+
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage bookmarkStorage) {
+ String line = input.substring(LIST_LENGTH).toLowerCase().trim();
+ if (line.contains("-")) {
+ if (line.contains("-s")) {
+ executeListStarCommand(ui, categories, line);
+ } else if (line.contains("-c")) {
+ executeListCatCommand(ui, categories, line);
+ } else if (line.contains("-a")) {
+ executeListAllCommand(ui, categories, line);
+ } else {
+ ui.showCorrectCommand("list");
+ }
+ } else {
+ if (line.length() > 0) {
+ ui.showCorrectCommand("list");
+ } else {
+ if (categoryNumber == 0) {
+ ui.showBookmarkList(categories);
+ } else {
+ assert categoryNumber > 0 : "Category number cannot be accessed";
+ ui.showBookmarkLinkList(categories.get(categoryNumber - 1));
+ }
+ printCurrentMode(ui, categories);
+ }
+ }
+ }
+
+ private void printCurrentMode(BookmarkUi ui, ArrayList categories) {
+ if (categoryNumber == 0) {
+ ui.showCurrentMode("Bookmark Main");
+ } else {
+ ui.showCurrentMode(categories.get(categoryNumber - 1).getName() + " category");
+ assert categoryNumber > 0 : "Cannot print category name when it is not available";
+ }
+ }
+
+ private void executeListCatCommand(BookmarkUi ui, ArrayList categories, String line) {
+ if (line.substring(2).length() > 0) {
+ ui.showCorrectCommand("list -c");
+ } else {
+ ui.showBookmarkCategoryList(categories);
+ printCurrentMode(ui, categories);
+ }
+ }
+
+ private void executeListStarCommand(BookmarkUi ui, ArrayList categories, String line) {
+ if (line.substring(2).length() > 0) {
+ ui.showCorrectCommand("list -s");
+ } else {
+ ui.showStarBookmarks(categories);
+ }
+ }
+
+ private void executeListAllCommand(BookmarkUi ui, ArrayList categories, String line) {
+ if (line.substring(2).length() > 0) {
+ ui.showCorrectCommand("list -a");
+ } else {
+ ui.showBookmarkList(categories);
+ printCurrentMode(ui, categories);
+ }
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+
+}
diff --git a/src/main/java/bookmark/commands/RemoveCategoryCommand.java b/src/main/java/bookmark/commands/RemoveCategoryCommand.java
new file mode 100644
index 0000000000..139b7c42a5
--- /dev/null
+++ b/src/main/java/bookmark/commands/RemoveCategoryCommand.java
@@ -0,0 +1,80 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.EmptyBookmarkException;
+import exceptions.ExistingBookmarkException;
+import exceptions.InvalidBookmarkException;
+
+import java.util.ArrayList;
+
+public class RemoveCategoryCommand extends BookmarkCommand {
+ public static final int DELETE_LENGTH = 6;
+ private int catNumber;
+ private int categoryNumber;
+ private String line;
+
+ public RemoveCategoryCommand(String line, int categoryNumber) {
+ this.categoryNumber = categoryNumber;
+ this.line = line.trim();
+ assert line.toLowerCase().startsWith("delete") : "Delete category command is called wrongly";
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Remove existing BookmarkLink from ArrayList after evaluating bookmark link number.
+ *
+ * @param ui prints output message
+ * @param categories remove link to array list
+ * @param storage remove link from file
+ * @throws EmptyBookmarkException if link number is empty
+ * @throws NumberFormatException if number is not the input
+ * @throws IndexOutOfBoundsException if number exceed large number
+ * @throws InvalidBookmarkException if bookmark link number is invalid.
+ */
+
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage storage) {
+ try {
+ if (categoryNumber != 0) {
+ System.out.println("Please go back to main bookmark menu to delete a category");
+ assert categoryNumber > 0 : "Choose Category message is called when category number is chosen";
+ } else if (line.length() <= DELETE_LENGTH) {
+ throw new EmptyBookmarkException();
+ } else {
+ line = line.substring(DELETE_LENGTH);
+ assert line.length() > 0 : "Link should not be empty";
+ catNumber = evaluateLinkNumber(categories);
+ System.out.println("Deleting Category: " + categories.get(catNumber - 1).getName());
+ categories.remove(catNumber - 1);
+ ui.showBookmarkCategoryList(categories);
+ storage.saveLinksToFile(categories);
+ }
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Category Number");
+ } catch (InvalidBookmarkException e) {
+ ui.showInvalidError("Category Number");
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ ui.showInvalidNumberError();
+ }
+ }
+
+ private int evaluateLinkNumber(ArrayList categories)
+ throws NumberFormatException, InvalidBookmarkException {
+ line = line.trim();
+ int catNum = Integer.parseInt(line);
+ if (catNum == 0 || catNum > categories.size()) {
+ throw new InvalidBookmarkException();
+ }
+ return catNum;
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+}
+
+
+
+
+
diff --git a/src/main/java/bookmark/commands/RemoveLinkCommand.java b/src/main/java/bookmark/commands/RemoveLinkCommand.java
new file mode 100644
index 0000000000..c9cd4fc0e0
--- /dev/null
+++ b/src/main/java/bookmark/commands/RemoveLinkCommand.java
@@ -0,0 +1,75 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.InvalidBookmarkException;
+import exceptions.EmptyBookmarkException;
+
+import java.util.ArrayList;
+
+public class RemoveLinkCommand extends BookmarkCommand {
+ public static final int RM_LENGTH = 2;
+ private int linkNumber;
+ private int categoryNumber;
+ private String line;
+
+ public RemoveLinkCommand(String line, int categoryNumber) {
+ this.categoryNumber = categoryNumber;
+ this.line = line.trim();
+ assert line.startsWith("rm") : "Remove link command is called when line does not start with rm";
+ assert categoryNumber >= 0 : "Missing category number";
+ }
+
+ /**
+ * Remove existing BookmarkCategory from ArrayList after evaluating bookmark category number.
+ *
+ * @param ui prints output message
+ * @param categories remove category to array list
+ * @param storage remove category from file
+ * @throws EmptyBookmarkException if category number is empty
+ * @throws NumberFormatException if number is not the input
+ * @throws IndexOutOfBoundsException if number exceed large number
+ * @throws InvalidBookmarkException if bookmark category number is invalid (0, more than category size).
+ */
+
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage storage) {
+ try {
+ if (categoryNumber == 0) {
+ ui.printChooseCategoryMessage();
+ assert categoryNumber == 0 : "Choose Category message is called when category number is chosen";
+ } else if (line.length() <= RM_LENGTH) {
+ throw new EmptyBookmarkException();
+ } else {
+ line = line.substring(RM_LENGTH);
+ assert line.length() > 0 : "Link should not be empty";
+ linkNumber = evaluateLinkNumber(categories);
+ System.out.println("Removing link: "
+ + categories.get(categoryNumber - 1).getLinks().get(linkNumber - 1));
+ categories.get(categoryNumber - 1).removeLink(linkNumber);
+ ui.showBookmarkLinkList(categories.get(categoryNumber - 1));
+ storage.saveLinksToFile(categories);
+ }
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Link Number");
+ } catch (InvalidBookmarkException e) {
+ ui.showInvalidError("Link Number");
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ ui.showInvalidNumberError();
+ }
+ }
+
+ private int evaluateLinkNumber(ArrayList categories)
+ throws NumberFormatException, InvalidBookmarkException {
+ line = line.trim();
+ int linkNum = Integer.parseInt(line);
+ if (linkNum == 0 || linkNum > categories.get(categoryNumber - 1).getLinks().size()) {
+ throw new InvalidBookmarkException();
+ }
+ return linkNum;
+ }
+
+ public int getCategoryNumber() {
+ return categoryNumber;
+ }
+}
diff --git a/src/main/java/bookmark/commands/StarCommand.java b/src/main/java/bookmark/commands/StarCommand.java
new file mode 100644
index 0000000000..941e7a66a1
--- /dev/null
+++ b/src/main/java/bookmark/commands/StarCommand.java
@@ -0,0 +1,70 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import exceptions.EmptyBookmarkException;
+import exceptions.InvalidBookmarkException;
+
+import java.util.ArrayList;
+
+public class StarCommand extends BookmarkCommand {
+ public static final int STAR_LENGTH = 4;
+ private int chosenCategory;
+ private String line;
+ private int starLinkNumber;
+
+ public StarCommand(String line, int chosenCategory) {
+ this.line = line.trim();
+ this.chosenCategory = chosenCategory;
+ }
+
+ /**
+ * Mark existing BookmarkLink as star or unstar existing BookmarkLink.
+ *
+ * @param ui prints output message
+ * @param categories star link in array list
+ * @param storage update starred link in file
+ * @throws EmptyBookmarkException if link number is empty
+ * @throws NumberFormatException if number is not the input
+ * @throws IndexOutOfBoundsException if number exceed large number
+ * @throws InvalidBookmarkException if bookmark link number is invalid.
+ */
+
+ public void executeCommand(BookmarkUi ui, ArrayList categories, BookmarkStorage storage) {
+ try {
+ if (chosenCategory == 0) {
+ ui.printChooseCategoryMessage();
+ } else if (line.length() <= STAR_LENGTH) {
+ throw new EmptyBookmarkException();
+ } else {
+ assert chosenCategory > 0 : "Category number is not chosen";
+ evaluateStarNumber(categories);
+ categories.get(chosenCategory - 1).markLinkAsStar(starLinkNumber - 1);
+ ui.showBookmarkLinkList(categories.get(chosenCategory - 1));
+ ui.showStarBookmarks(categories);
+ storage.saveLinksToFile(categories);
+ }
+ } catch (EmptyBookmarkException e) {
+ ui.showEmptyError("Star Number");
+ } catch (InvalidBookmarkException e) {
+ ui.showInvalidError("Star Number");
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ ui.showInvalidNumberError();
+ }
+ }
+
+ private void evaluateStarNumber(ArrayList categories)
+ throws NumberFormatException, InvalidBookmarkException {
+ line = line.substring(STAR_LENGTH).trim();
+ int catNum = Integer.parseInt(line);
+ if (catNum == 0 || catNum > categories.get(chosenCategory - 1).getLinks().size()) {
+ throw new InvalidBookmarkException();
+ }
+ starLinkNumber = catNum;
+ }
+
+ public int getCategoryNumber() {
+ return chosenCategory;
+ }
+}
diff --git a/src/main/java/exceptions/ClashScheduleException.java b/src/main/java/exceptions/ClashScheduleException.java
new file mode 100644
index 0000000000..dfdba5b651
--- /dev/null
+++ b/src/main/java/exceptions/ClashScheduleException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class ClashScheduleException extends Exception {
+}
diff --git a/src/main/java/exceptions/EmptyBookmarkException.java b/src/main/java/exceptions/EmptyBookmarkException.java
new file mode 100644
index 0000000000..881a9b67ed
--- /dev/null
+++ b/src/main/java/exceptions/EmptyBookmarkException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class EmptyBookmarkException extends Exception{
+}
diff --git a/src/main/java/exceptions/EmptyInputException.java b/src/main/java/exceptions/EmptyInputException.java
new file mode 100644
index 0000000000..40bfbdc1d5
--- /dev/null
+++ b/src/main/java/exceptions/EmptyInputException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class EmptyInputException extends Exception{
+}
diff --git a/src/main/java/exceptions/ExistingBookmarkException.java b/src/main/java/exceptions/ExistingBookmarkException.java
new file mode 100644
index 0000000000..ddce35d466
--- /dev/null
+++ b/src/main/java/exceptions/ExistingBookmarkException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class ExistingBookmarkException extends Exception{
+}
diff --git a/src/main/java/exceptions/InvalidBookmarkException.java b/src/main/java/exceptions/InvalidBookmarkException.java
new file mode 100644
index 0000000000..4216b05a6e
--- /dev/null
+++ b/src/main/java/exceptions/InvalidBookmarkException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidBookmarkException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidCommandException.java b/src/main/java/exceptions/InvalidCommandException.java
new file mode 100644
index 0000000000..b2123268b8
--- /dev/null
+++ b/src/main/java/exceptions/InvalidCommandException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidCommandException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidDayOfTheWeekException.java b/src/main/java/exceptions/InvalidDayOfTheWeekException.java
new file mode 100644
index 0000000000..d9b195f68e
--- /dev/null
+++ b/src/main/java/exceptions/InvalidDayOfTheWeekException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidDayOfTheWeekException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidEmailException.java b/src/main/java/exceptions/InvalidEmailException.java
new file mode 100644
index 0000000000..2c18810848
--- /dev/null
+++ b/src/main/java/exceptions/InvalidEmailException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidEmailException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidGradeException.java b/src/main/java/exceptions/InvalidGradeException.java
new file mode 100644
index 0000000000..dd8dae99e8
--- /dev/null
+++ b/src/main/java/exceptions/InvalidGradeException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidGradeException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidMcException.java b/src/main/java/exceptions/InvalidMcException.java
new file mode 100644
index 0000000000..cb5c7d8a78
--- /dev/null
+++ b/src/main/java/exceptions/InvalidMcException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidMcException extends Exception{
+}
diff --git a/src/main/java/exceptions/InvalidModeException.java b/src/main/java/exceptions/InvalidModeException.java
new file mode 100644
index 0000000000..14c0c64c9a
--- /dev/null
+++ b/src/main/java/exceptions/InvalidModeException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidModeException extends Exception {
+}
diff --git a/src/main/java/exceptions/InvalidTimeException.java b/src/main/java/exceptions/InvalidTimeException.java
new file mode 100644
index 0000000000..e80fb58e02
--- /dev/null
+++ b/src/main/java/exceptions/InvalidTimeException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class InvalidTimeException extends Exception{
+}
diff --git a/src/main/java/exceptions/RepeatedGradeException.java b/src/main/java/exceptions/RepeatedGradeException.java
new file mode 100644
index 0000000000..39b35942ae
--- /dev/null
+++ b/src/main/java/exceptions/RepeatedGradeException.java
@@ -0,0 +1,4 @@
+package exceptions;
+
+public class RepeatedGradeException extends Exception{
+}
diff --git a/src/main/java/flashcard/Flashcard.java b/src/main/java/flashcard/Flashcard.java
new file mode 100644
index 0000000000..e11810538f
--- /dev/null
+++ b/src/main/java/flashcard/Flashcard.java
@@ -0,0 +1,16 @@
+package flashcard;
+
+public class Flashcard {
+
+ public String question;
+ public String answer;
+
+ public Flashcard(String question, String answer) {
+ this.question = question;
+ this.answer = answer;
+ }
+
+ public String writeToFile() {
+ return question + "|" + answer + "\n";
+ }
+}
diff --git a/src/main/java/flashcard/FlashcardDeck.java b/src/main/java/flashcard/FlashcardDeck.java
new file mode 100644
index 0000000000..bab0f91a46
--- /dev/null
+++ b/src/main/java/flashcard/FlashcardDeck.java
@@ -0,0 +1,168 @@
+package flashcard;
+
+import userinterface.Ui;
+
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+public class FlashcardDeck {
+
+ public static final String BACK = "back";
+ public static final String SHOW_ANSWER = "show answer";
+ public ArrayList flashcardDeck;
+
+ public FlashcardDeck() {
+ flashcardDeck = new ArrayList();
+ }
+
+ public void addCards() {
+ Ui.printDivider();
+ Scanner in = new Scanner(System.in);
+ System.out.println("Please enter question: ");
+ final String question = in.nextLine();
+ System.out.println("Please enter answer: ");
+ String answer = in.nextLine();
+ while (answer.equalsIgnoreCase(BACK)) {
+ System.out.println("The answer cannot be \"back\"! Please enter another answer: ");
+ answer = in.nextLine();
+ }
+ while (answer.equalsIgnoreCase(SHOW_ANSWER)) {
+ System.out.println("The answer cannot be \"show answer\"! Please enter another answer: ");
+ answer = in.nextLine();
+ }
+ Ui.printDivider();
+ flashcardDeck.add(new Flashcard(question, answer));
+ System.out.println("You have successfully created the flashcard below: \n"
+ + "Question: " + question + "\n"
+ + "Answer: " + answer);
+ Ui.printDivider();
+ }
+
+ public void listCards() {
+ Ui.printDivider();
+ if (flashcardDeck.size() == 0) {
+ System.out.println("There are no cards in your deck!\n"
+ + "Use \"add\" to add flashcards.");
+ } else {
+ System.out.println("Here is the list of flashcards you have: ");
+ int cardIndex = 1;
+ for (Flashcard flashcard : flashcardDeck) {
+ System.out.println(cardIndex + ". " + flashcard.question + "|" + flashcard.answer);
+ cardIndex++;
+ }
+ }
+ Ui.printDivider();
+ }
+
+ public void testRandomCard() {
+ if (flashcardDeck.size() > 0) {
+ Scanner in = new Scanner(System.in);
+ int score = 0;
+ Ui.printDivider();
+ System.out.println("You have entered the test mode.\n"
+ + "Use \"back\" to return to flashcard main, or \"show answer\" to reveal answer.");
+ Ui.printDivider();
+ String attempt = "null";
+ while (!attempt.equalsIgnoreCase(BACK)) {
+ Random random = new Random();
+ int randomIndex = random.nextInt(flashcardDeck.size());
+ System.out.println("What is the answer to this question?");
+ System.out.println(flashcardDeck.get(randomIndex).question);
+ attempt = in.nextLine();
+ while (!attempt.equalsIgnoreCase(flashcardDeck.get(randomIndex).answer)
+ && !attempt.equalsIgnoreCase(BACK) && !attempt.equalsIgnoreCase(SHOW_ANSWER)) {
+ System.out.println("Incorrect! Try again?");
+ attempt = in.nextLine();
+ }
+ if (attempt.equalsIgnoreCase(BACK)) {
+ Ui.printDivider();
+ System.out.println("Exiting test mode...\n"
+ + "You are now back in flashcard main.");
+ } else if (attempt.equalsIgnoreCase(SHOW_ANSWER)) {
+ Ui.printDivider();
+ System.out.println("The answer for this question is: " + flashcardDeck.get(randomIndex).answer);
+ } else {
+ score++;
+ System.out.print("This is the right answer! ");
+ if (score == 1) {
+ System.out.println("You now have " + score + " point.");
+ } else {
+ System.out.println("You now have " + score + " points.");
+ }
+ }
+ Ui.printDivider();
+ }
+ } else {
+ Ui.printDivider();
+ System.out.println("There are no cards in your deck to test from!\n"
+ + "Use \"add\" to add flashcards, before testing yourself.");
+ Ui.printDivider();
+ }
+ }
+
+ public void deleteCard() {
+ Scanner in = new Scanner(System.in);
+ Ui.printDivider();
+ System.out.println("Please enter the index of the card you wish to delete.");
+ String userInput = in.nextLine();
+ int cardIndex = 0;
+ try {
+ cardIndex = Integer.parseInt(userInput);
+ if (flashcardDeck.size() == 0) {
+ Ui.printDivider();
+ System.out.println("You do not have any cards in your deck!\n"
+ + "Please use \"add\" to add flashcards to your deck.");
+ Ui.printDivider();
+ } else if (cardIndex == 0 || cardIndex < 0) {
+ Ui.printDivider();
+ System.out.println("Please enter a card index greater than 0!");
+ Ui.printDivider();
+ } else if (cardIndex > flashcardDeck.size()) {
+ Ui.printDivider();
+ System.out.println("Sorry, you only have " + flashcardDeck.size() + " cards in your deck!\n"
+ + "Please enter a number within the range of 1-" + flashcardDeck.size() + ".");
+ Ui.printDivider();
+ } else {
+ assert cardIndex <= flashcardDeck.size() : "card index inserted should be less than size of deck "
+ + "at this step";
+ Ui.printDivider();
+ System.out.println("Noted. I have removed this card: "
+ + flashcardDeck.get(cardIndex - 1).question + "|" + flashcardDeck.get(cardIndex - 1).answer
+ + "\n" + "Now you have " + (flashcardDeck.size() - 1) + " cards in the list.");
+ Ui.printDivider();
+ flashcardDeck.remove(cardIndex - 1);
+ }
+ } catch (NumberFormatException e) {
+ Ui.printDivider();
+
+ System.out.println("Please enter the index of the card as an integer!");
+ Ui.printDivider();
+ }
+ }
+
+ public void findCard() {
+ int numberOfCardsFound = 0;
+ Scanner in = new Scanner(System.in);
+ Ui.printDivider();
+ System.out.println("Please enter a search term: ");
+ String searchItem = in.nextLine();
+ ArrayList cardsFound = (ArrayList) flashcardDeck.stream()
+ .filter((flashcard) -> flashcard.question.toLowerCase().contains(searchItem.toLowerCase()))
+ .collect((Collectors.toList()));
+ if (cardsFound.size() == 0) {
+ Ui.printDivider();
+ System.out.println("There are no matching cards in your list.");
+ Ui.printDivider();
+ } else {
+ Ui.printDivider();
+ System.out.println("Here are the matching cards in your list:");
+ for (Flashcard flashcard: cardsFound) {
+ numberOfCardsFound++;
+ System.out.println(numberOfCardsFound + ". " + flashcard.question + "|" + flashcard.answer);
+ }
+ Ui.printDivider();
+ }
+ }
+}
diff --git a/src/main/java/flashcard/FlashcardRun.java b/src/main/java/flashcard/FlashcardRun.java
new file mode 100644
index 0000000000..0e8398f6bf
--- /dev/null
+++ b/src/main/java/flashcard/FlashcardRun.java
@@ -0,0 +1,58 @@
+package flashcard;
+
+import studyit.StudyItLog;
+import userinterface.Ui;
+
+import java.io.IOException;
+import java.util.Scanner;
+
+public class FlashcardRun {
+ public static final String TEST = "test";
+ public static final String DELETE = "delete";
+ public static final String FIND = "find";
+ public FlashcardDeck flashcardDeck;
+ public FlashcardStorage storage;
+ public static final String ADD = "add";
+ public static final String LIST = "list";
+ public static final String EXIT = "exit";
+
+ public FlashcardRun() {
+ flashcardDeck = new FlashcardDeck();
+ try {
+ storage = new FlashcardStorage("data/flashcard.txt");
+ storage.readFromFile(flashcardDeck);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ StudyItLog.logger.info("Flashcard mode initialized");
+ }
+
+ public void run(String command) {
+ switch (command) {
+ case ADD:
+ flashcardDeck.addCards();
+ break;
+ case DELETE:
+ flashcardDeck.deleteCard();
+ break;
+ case LIST:
+ flashcardDeck.listCards();
+ break;
+ case TEST:
+ flashcardDeck.testRandomCard();
+ break;
+ case FIND:
+ flashcardDeck.findCard();
+ break;
+ default:
+ Ui.printDivider();
+ System.out.println("Invalid command. Valid commands are \"add\", \"delete\", \"list\", "
+ + "\"test\" and \"find\"."
+ + "\nUse \"exit\" to exit the flashcard mode.");
+ Ui.printDivider();
+ StudyItLog.logger.warning("Invalid flashcard command: Command unidentifiable");
+ }
+ storage.writeToFile(flashcardDeck);
+ }
+}
diff --git a/src/main/java/flashcard/FlashcardStorage.java b/src/main/java/flashcard/FlashcardStorage.java
new file mode 100644
index 0000000000..dfa20a739d
--- /dev/null
+++ b/src/main/java/flashcard/FlashcardStorage.java
@@ -0,0 +1,64 @@
+package flashcard;
+
+import studyit.StudyItLog;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class FlashcardStorage {
+
+ public ArrayList flashcardDeck;
+ private final File file;
+ private static final String dirPath = "data";
+ private final String filePath;
+
+ public FlashcardStorage(String filePath) throws IOException {
+ // Creates the data directory
+ File fileDir = new File(dirPath);
+
+ if (!fileDir.exists()) {
+ fileDir.mkdir();
+ }
+
+ file = new File(filePath);
+ this.filePath = filePath;
+ }
+
+ public void writeToFile(FlashcardDeck flashcardDeck) {
+ try {
+ FileWriter fw = new FileWriter(filePath);
+ for (Flashcard flashcard : flashcardDeck.flashcardDeck) {
+ fw.write(flashcard.writeToFile());
+ }
+ fw.close();
+ } catch (IOException e) {
+ System.out.println("Something went wrong!" + e.getMessage());
+ StudyItLog.logger.warning("Problem writing to flashcard storage file\n" + e);
+ }
+ }
+
+ public void readFromFile(FlashcardDeck flashcardDeck) throws IOException {
+ try {
+ Scanner s = new Scanner(file);
+ Flashcard flashcard;
+ while (s.hasNext()) {
+ String[] parseCard = s.nextLine().split("\\|");
+ String question = parseCard[0];
+ String answer = parseCard[1];
+ flashcard = new Flashcard(question, answer);
+ flashcardDeck.flashcardDeck.add(flashcard);
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("data/flashcard.txt is not found, creating a new file now!");
+
+ file.createNewFile();
+
+ StudyItLog.logger.info(e + "\nflashcard storage file created");
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
index 5c74e68d59..0dbe0ff9c3 100644
--- a/src/main/java/seedu/duke/Duke.java
+++ b/src/main/java/seedu/duke/Duke.java
@@ -1,5 +1,7 @@
package seedu.duke;
+import flashcard.FlashcardDeck;
+
import java.util.Scanner;
public class Duke {
@@ -17,5 +19,7 @@ public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Hello " + in.nextLine());
+ FlashcardDeck flashcardDeck = new FlashcardDeck();
}
}
+
diff --git a/src/main/java/studyit/Command.java b/src/main/java/studyit/Command.java
new file mode 100644
index 0000000000..9392d8d693
--- /dev/null
+++ b/src/main/java/studyit/Command.java
@@ -0,0 +1,101 @@
+package studyit;
+
+import flashcard.FlashcardRun;
+import timetable.TimeTableRun;
+import userinterface.ErrorMessage;
+import userinterface.HelpMessage;
+import userinterface.Ui;
+import bookmark.BookmarkRun;
+import academic.AcademicRun;
+
+
+public class Command {
+
+ /**
+ * Handles the user input command.
+ * It executes the command if it is a general command. Otherwise, it will
+ * pass the command to each respective mode to handle under handleNonGeneralCommand()
+ *
+ * @param command Raw string input of the user command
+ * @param commandType Identifies which command type it is (passed in by command parser)
+ * @param bookmarkRun Main component for bookmark mode
+ * @param flashcardRun Main component for flashcard mode
+ * @param timeTableRun Main component for timetable mode
+ * @param academicRun Main component for academic mode
+ */
+ public static void executeCommand(String command, CommandType commandType,
+ BookmarkRun bookmarkRun, FlashcardRun flashcardRun,
+ TimeTableRun timeTableRun, AcademicRun academicRun) {
+ if (commandType == CommandType.EXIT_PROGRAM) {
+ Ui.printExit();
+ } else if (commandType == CommandType.EXIT_MODE) {
+ Ui.exitMode();
+ } else if (commandType == CommandType.LOCATION) {
+ Ui.printLocation();
+ } else if (commandType == CommandType.CHANGE_MODE) {
+ Ui.changeModeCommand(command);
+ } else if (commandType == CommandType.HELP) {
+ HelpMessage.printHelpMessage();
+ } else if (commandType == CommandType.HIGHLIGHT) {
+ Ui.printHighlight(bookmarkRun, academicRun);
+ } else if (StudyIt.getCurrentMode() != Mode.MENU) {
+ // Run the mode specific commands if the input is none of the general command
+ handleNonGeneralCommand(command, bookmarkRun, flashcardRun, timeTableRun,
+ academicRun);
+ } else {
+ assert commandType == CommandType.UNIDENTIFIABLE : "This command should be unidentifiable";
+ ErrorMessage.printUnidentifiableCommand();
+ }
+ }
+
+ /**
+ * Handles the non-general command such as commands under different modes.
+ *
+ * @param command raw string of the user input
+ * @param bookmarkRun Main component for bookmark mode
+ * @param flashcardRun Main component for flashcard mode
+ * @param timeTableRun Main component for timetable mode
+ * @param academicRun Main component for academic mode
+ */
+ public static void handleNonGeneralCommand(String command, BookmarkRun bookmarkRun,
+ FlashcardRun flashcardRun, TimeTableRun timeTableRun,
+ AcademicRun academicRun) {
+ Mode currentMode = StudyIt.getCurrentMode();
+ if (currentMode == Mode.BOOKMARK) {
+ executeBookmarkModeCommand(command, bookmarkRun);
+ } else if (currentMode == Mode.TIMETABLE) {
+ executeTimetableModeCommand(command, timeTableRun);
+ } else if (currentMode == Mode.ACADEMIC) {
+ executeAcademicModeCommand(command, academicRun);
+ } else if (currentMode == Mode.FLASHCARD) {
+ executeFlashcardCommand(command, flashcardRun);
+ } else {
+ assert currentMode == Mode.MENU : "The current mode should be at menu";
+ StudyItLog.logger.severe("Mode is not handled properly.");
+ }
+ }
+
+ public static void executeBookmarkModeCommand(String command, BookmarkRun bookmarkRun) {
+ StudyItLog.logger.info("Processing bookmark command: " + command);
+ Ui.printDivider();
+ bookmarkRun.run(command);
+ Ui.printDivider();
+ }
+
+ public static void executeTimetableModeCommand(String command, TimeTableRun timeTableRun) {
+ StudyItLog.logger.info("Processing timetable command: " + command);
+ Ui.printDivider();
+ timeTableRun.run(command);
+ Ui.printDivider();
+ }
+
+ public static void executeAcademicModeCommand(String command, AcademicRun academicRun) {
+ StudyItLog.logger.info("Processing academic command: " + command);
+ academicRun.run(command);
+ }
+
+ public static void executeFlashcardCommand(String command, FlashcardRun flashcardRun) {
+ StudyItLog.logger.info("Processing flashcard command: " + command);
+ flashcardRun.run(command);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/CommandParser.java b/src/main/java/studyit/CommandParser.java
new file mode 100644
index 0000000000..3d26677867
--- /dev/null
+++ b/src/main/java/studyit/CommandParser.java
@@ -0,0 +1,69 @@
+package studyit;
+
+import exceptions.InvalidModeException;
+
+public class CommandParser {
+
+ /**
+ * Standardize the command to lowercase and trimmed.
+ *
+ * @param text String text
+ * @return the standardized command
+ */
+ public static String standardizeCommand(String text) {
+ return text.trim().toLowerCase();
+ }
+
+ /**
+ * Identifies the general commands.
+ * @param command raw string of the user input
+ * @return the command type of the command
+ */
+ public static CommandType getCommandType(String command) {
+ String commandModified = standardizeCommand(command);
+
+ if ((StudyIt.getCurrentMode() == Mode.MENU) && (commandModified.equals("exit"))) {
+ return CommandType.EXIT_PROGRAM;
+ } else if (commandModified.equals("exit")) {
+ return CommandType.EXIT_MODE;
+ } else if (commandModified.equals("location")) {
+ return CommandType.LOCATION;
+ } else if (commandModified.startsWith("cd")) {
+ return CommandType.CHANGE_MODE;
+ } else if (commandModified.equals("help")) {
+ return CommandType.HELP;
+ } else if (commandModified.equals("highlight")) {
+ return CommandType.HIGHLIGHT;
+ } else {
+ return CommandType.UNIDENTIFIABLE;
+ }
+ }
+
+ /**
+ * Parses which mode to switch to for "cd" command.
+ *
+ * @param command raw string of user input
+ * @return the destination mode
+ * @throws InvalidModeException The mode index inserted is not available
+ */
+ public static Mode getDestinationMode(String command) throws InvalidModeException {
+ String commandModified = standardizeCommand(command);
+ int initialLength = "cd".length();
+ String destination = commandModified.substring(initialLength).trim();
+
+ if (destination.equals("1") || destination.equals(ModeNames.MENU_NAME)) {
+ return Mode.MENU;
+ } else if (destination.equals("2") || destination.equals(ModeNames.BOOKMARK_NAME)) {
+ return Mode.BOOKMARK;
+ } else if (destination.equals("3") || destination.equals(ModeNames.TIMETABLE_NAME)) {
+ return Mode.TIMETABLE;
+ } else if (destination.equals("4") || destination.equals(ModeNames.ACADEMIC_NAME)) {
+ return Mode.ACADEMIC;
+ } else if (destination.equals("5") || destination.equals(ModeNames.FLASHCARD_NAME)) {
+ return Mode.FLASHCARD;
+ } else {
+ StudyItLog.logger.info("Invalid mode was chosen.");
+ throw new InvalidModeException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/CommandType.java b/src/main/java/studyit/CommandType.java
new file mode 100644
index 0000000000..147a1d4f7f
--- /dev/null
+++ b/src/main/java/studyit/CommandType.java
@@ -0,0 +1,11 @@
+package studyit;
+
+public enum CommandType {
+ EXIT_PROGRAM,
+ EXIT_MODE,
+ LOCATION,
+ CHANGE_MODE,
+ UNIDENTIFIABLE,
+ HELP,
+ HIGHLIGHT
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/Mode.java b/src/main/java/studyit/Mode.java
new file mode 100644
index 0000000000..503520dd3f
--- /dev/null
+++ b/src/main/java/studyit/Mode.java
@@ -0,0 +1,9 @@
+package studyit;
+
+public enum Mode {
+ MENU,
+ BOOKMARK,
+ TIMETABLE,
+ ACADEMIC,
+ FLASHCARD
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/ModeNames.java b/src/main/java/studyit/ModeNames.java
new file mode 100644
index 0000000000..c3b9a4ba7c
--- /dev/null
+++ b/src/main/java/studyit/ModeNames.java
@@ -0,0 +1,26 @@
+package studyit;
+
+public class ModeNames {
+ public static final String BOOKMARK_NAME = "bookmark";
+ public static final String TIMETABLE_NAME = "timetable";
+ public static final String ACADEMIC_NAME = "academic";
+ public static final String FLASHCARD_NAME = "flashcard";
+ public static final String MENU_NAME = "menu";
+
+ public static String getCurrentModeName() {
+ Mode currentMode = StudyIt.getCurrentMode();
+
+ switch (currentMode) {
+ case BOOKMARK:
+ return BOOKMARK_NAME;
+ case TIMETABLE:
+ return TIMETABLE_NAME;
+ case ACADEMIC:
+ return ACADEMIC_NAME;
+ case FLASHCARD:
+ return FLASHCARD_NAME;
+ default:
+ return MENU_NAME;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/StudyIt.java b/src/main/java/studyit/StudyIt.java
new file mode 100644
index 0000000000..7c3b0fb778
--- /dev/null
+++ b/src/main/java/studyit/StudyIt.java
@@ -0,0 +1,72 @@
+package studyit;
+
+import academic.AcademicRun;
+import timetable.TimeTableRun;
+import flashcard.FlashcardRun;
+import userinterface.MainMenu;
+import userinterface.Ui;
+import bookmark.BookmarkRun;
+
+
+
+public class StudyIt {
+ private static Mode currentMode = Mode.MENU;
+ private BookmarkRun bookmarkRun;
+ private TimeTableRun timeTableRun;
+ private FlashcardRun flashcardRun;
+ private AcademicRun academicRun;
+
+ public static void changeMode(Mode destinationMode) {
+ currentMode = destinationMode;
+ }
+
+ public static Mode getCurrentMode() {
+ return currentMode;
+ }
+
+ /**
+ * Sets up each mode (bookmark,timetable,flashcard,academic).
+ */
+ public StudyIt() {
+ StudyItLog.setUpLogger();
+ StudyItLog.logger.info("Initializing program");
+ bookmarkRun = new BookmarkRun();
+ timeTableRun = new TimeTableRun();
+ flashcardRun = new FlashcardRun();
+ academicRun = new AcademicRun();
+ StudyItLog.logger.info("Program initialized");
+ }
+
+ /**
+ * Main method for Study It. Initializes Study It and enter the running process.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ StudyIt studyIt = new StudyIt();
+ MainMenu.printWelcome();
+ studyIt.run();
+ }
+
+ /**
+ * Main running program of Study it. Keeps the program in a constant loop
+ * until the exit command is called. It'll take in user input and process them.
+ */
+ public void run() {
+ CommandType commandType;
+ StudyItLog.logger.info("Executing program");
+ // Repeatedly receive & process user command until "exit" is given
+ do {
+ // Collect user's command & identify the type
+ String command = Ui.inputCommand();
+ commandType = CommandParser.getCommandType(command);
+
+ StudyItLog.logger.info("Command received: " + command);
+ StudyItLog.logger.info("Command type identified: " + commandType);
+
+ Command.executeCommand(command, commandType, bookmarkRun, flashcardRun,
+ timeTableRun, academicRun);
+ } while (commandType != CommandType.EXIT_PROGRAM);
+
+ StudyItLog.logger.info("End of program.");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/studyit/StudyItLog.java b/src/main/java/studyit/StudyItLog.java
new file mode 100644
index 0000000000..976d147736
--- /dev/null
+++ b/src/main/java/studyit/StudyItLog.java
@@ -0,0 +1,42 @@
+package studyit;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Logger;
+import java.util.logging.LogManager;
+import java.util.logging.Level;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.FileHandler;
+import java.util.logging.SimpleFormatter;
+
+
+public class StudyItLog {
+ public static Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+
+ public static void setUpLogger() {
+ LogManager.getLogManager().reset();
+ logger.setLevel(Level.ALL);
+
+ ConsoleHandler ch = new ConsoleHandler();
+ ch.setLevel(Level.SEVERE);
+ logger.addHandler(ch);
+
+
+
+ try {
+ String dirPath = "logs";
+ File fileDir = new File(dirPath);
+
+ if (!fileDir.exists()) {
+ fileDir.mkdir();
+ }
+
+ FileHandler fh = new FileHandler("logs/StudyIt_Logger.log", true);
+ fh.setFormatter(new SimpleFormatter());
+ fh.setLevel(Level.FINE);
+ logger.addHandler(fh);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "File logger not working.", e);
+ }
+ }
+}
diff --git a/src/main/java/timetable/Activity.java b/src/main/java/timetable/Activity.java
new file mode 100644
index 0000000000..aa11d1b682
--- /dev/null
+++ b/src/main/java/timetable/Activity.java
@@ -0,0 +1,20 @@
+package timetable;
+
+public class Activity extends Event {
+
+ public Activity(String activityName, boolean isOnline, String linkOrVenue, Duration duration) {
+ super(activityName, isOnline, linkOrVenue, EventType.A);
+ super.addPeriod(duration);
+ assert super.periods.size() == 1 : "periods size should return 1";
+ }
+
+ @Override
+ public void addPeriod(Duration duration) {
+ }
+
+ @Override
+ public String getStorageString() {
+ return "|" + periods.get(0).startDateTime.toString()
+ + "|" + periods.get(0).endDateTime.toString();
+ }
+}
diff --git a/src/main/java/timetable/DateList.java b/src/main/java/timetable/DateList.java
new file mode 100644
index 0000000000..db69b100c4
--- /dev/null
+++ b/src/main/java/timetable/DateList.java
@@ -0,0 +1,116 @@
+package timetable;
+
+import exceptions.ClashScheduleException;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DateList {
+ public List dateList;
+ public List lessons;
+ public List activities;
+
+ public DateList() {
+ dateList = new ArrayList<>();
+ lessons = new ArrayList<>();
+ activities = new ArrayList<>();
+ }
+
+ public void addEvent(Event event) throws ClashScheduleException {
+ for (Duration duration: event.periods) {
+ boolean existList = false;
+ for (EventList eventList: dateList) {
+ if (eventList.dateTag.equals(duration.startDateTime.toLocalDate())) {
+ if (clashDetection(duration, eventList)) {
+ throw new ClashScheduleException();
+ } else {
+ eventList.addEvent(event);
+ existList = true;
+ }
+ }
+ }
+ if (!existList) {
+ EventList newList = new EventList(duration.startDateTime);
+ newList.addEvent(event);
+ dateList.add(newList);
+ }
+ }
+ }
+
+ public boolean clashDetection(Duration duration, EventList eventList) {
+ for (int i = 0; i < duration.timeSlot.size(); i++) {
+ for (Event event: eventList.events) {
+ for (Duration period: event.periods) {
+ if (duration.startDateTime.toLocalDate().equals(period.startDateTime.toLocalDate())
+ && period.containTimeSlot(duration.timeSlot.get(i))) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+
+ }
+
+ public void deleteActivity(int index, TimeTableStorage storage) {
+ activities.remove(index - 1);
+ dateList.clear();
+ storage.wipeFile();
+ for (Lesson lesson: lessons) {
+ try {
+ addEvent(lesson);
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule");
+ }
+ storage.writeFile(lesson);
+ }
+ for (Activity activity: activities) {
+ try {
+ addEvent(activity);
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule");
+ }
+ storage.writeFile(activity);
+ }
+ }
+
+ public void deleteLesson(int index, TimeTableStorage storage) {
+ lessons.remove(index - 1);
+ dateList.clear();
+ storage.wipeFile();
+ for (Lesson lesson: lessons) {
+ try {
+ addEvent(lesson);
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule");
+ }
+ storage.writeFile(lesson);
+ }
+ for (Activity activity: activities) {
+ try {
+ addEvent(activity);
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule");
+ }
+ storage.writeFile(activity);
+ }
+ }
+
+ public void cleanUpEvent(TimeTableStorage storage) {
+ for (int i = 0; i < activities.size(); i++) {
+ if (activities.get(i).periods.get(0).endDateTime.isBefore(LocalDateTime.now().minusDays(7))) {
+ deleteActivity(i + 1, storage);
+ i--;
+ }
+ }
+ for (int i = 0; i < lessons.size(); i++) {
+ int periodLastIndex = lessons.get(i).periods.size() - 1;
+ LocalDateTime lastDate = lessons.get(i).periods.get(periodLastIndex).endDateTime;
+ if (lastDate.isBefore(LocalDateTime.now().minusDays(7))) {
+ deleteLesson(i + 1, storage);
+ i--;
+ }
+ }
+ }
+}
diff --git a/src/main/java/timetable/Duration.java b/src/main/java/timetable/Duration.java
new file mode 100644
index 0000000000..952c68ab47
--- /dev/null
+++ b/src/main/java/timetable/Duration.java
@@ -0,0 +1,41 @@
+package timetable;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Duration {
+ public LocalDateTime startDateTime;
+ public LocalDateTime endDateTime;
+ public List timeSlot;
+
+ public Duration(LocalDateTime startDateTime, LocalDateTime endDateTime) {
+ this.startDateTime = startDateTime;
+ this.endDateTime = endDateTime;
+ timeSlot = new ArrayList<>();
+ int start = getTime(startDateTime);
+ int end = getTime(endDateTime);
+ for (int time = start; time < end; time += 100) {
+ timeSlot.add(time);
+ }
+ }
+
+ public Duration(LocalDateTime startDateTime) {
+ this.startDateTime = startDateTime;
+ this.endDateTime = startDateTime.plusHours(1);
+ timeSlot = new ArrayList<>();
+ int start = getTime(startDateTime);
+ int end = getTime(endDateTime);
+ for (int time = start; time < end; time += 100) {
+ timeSlot.add(time);
+ }
+ }
+
+ public int getTime(LocalDateTime dateTime) {
+ return dateTime.getHour() * 100 + dateTime.getMinute();
+ }
+
+ public boolean containTimeSlot(int timeSlot) {
+ return this.timeSlot.contains(timeSlot);
+ }
+}
diff --git a/src/main/java/timetable/Event.java b/src/main/java/timetable/Event.java
new file mode 100644
index 0000000000..a8b116c966
--- /dev/null
+++ b/src/main/java/timetable/Event.java
@@ -0,0 +1,27 @@
+package timetable;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class Event {
+ public String name;
+ public boolean isOnline;
+ public String linkOrVenue;
+ public List periods;
+ public EventType eventType;
+
+ public Event(String name, boolean isOnline, String linkOrVenue,EventType eventType) {
+ this.name = name;
+ this.isOnline = isOnline;
+ this.linkOrVenue = linkOrVenue;
+ periods = new ArrayList<>();
+ this.eventType = eventType;
+ }
+
+ public void addPeriod(Duration period) {
+ this.periods.add(period);
+ }
+
+ public abstract String getStorageString();
+}
diff --git a/src/main/java/timetable/EventList.java b/src/main/java/timetable/EventList.java
new file mode 100644
index 0000000000..b6e4b9d019
--- /dev/null
+++ b/src/main/java/timetable/EventList.java
@@ -0,0 +1,20 @@
+package timetable;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class EventList {
+ public LocalDate dateTag;
+ public List events;
+
+ public EventList(LocalDateTime dateTime) {
+ dateTag = dateTime.toLocalDate();
+ events = new ArrayList<>();
+ }
+
+ public void addEvent(Event event) {
+ events.add(event);
+ }
+}
diff --git a/src/main/java/timetable/EventType.java b/src/main/java/timetable/EventType.java
new file mode 100644
index 0000000000..1b50a936c5
--- /dev/null
+++ b/src/main/java/timetable/EventType.java
@@ -0,0 +1,5 @@
+package timetable;
+
+public enum EventType {
+ A,L
+}
diff --git a/src/main/java/timetable/Lesson.java b/src/main/java/timetable/Lesson.java
new file mode 100644
index 0000000000..dade9a74d2
--- /dev/null
+++ b/src/main/java/timetable/Lesson.java
@@ -0,0 +1,21 @@
+package timetable;
+
+public class Lesson extends Event {
+
+ public int numPerWeek;
+
+ public Lesson(String moduleCode, String linkOrVenue, boolean isOnline, int numPerWeek) {
+ super(moduleCode, isOnline,linkOrVenue,EventType.L);
+ this.numPerWeek = numPerWeek;
+ }
+
+ @Override
+ public String getStorageString() {
+ String storageString = "|" + numPerWeek + "|" + super.periods.size();
+ for (Duration period : super.periods) {
+ storageString = String.format("%s|%s", storageString, period.startDateTime.toString());
+ storageString = String.format("%s|%s", storageString, period.endDateTime.toString());
+ }
+ return storageString;
+ }
+}
diff --git a/src/main/java/timetable/Message.java b/src/main/java/timetable/Message.java
new file mode 100644
index 0000000000..33a1e271dc
--- /dev/null
+++ b/src/main/java/timetable/Message.java
@@ -0,0 +1,17 @@
+package timetable;
+
+public class Message {
+
+ public static final String printSuccessfulClassAddition = "This class has been added successfully! "
+ + "\nUse \"show schedule\" to view your timetable or use \"list class\" to see in the list form.";
+
+ public static final String printSuccessfulActivityAddition = "This activity has been added successfully! "
+ + "\nUse \"show schedule\" to view your schedule or use \"list activity\" to see in the list form.";
+
+ public static final String printShowSchedule = "This is your schedule for the next 7 days.";
+ public static final String printShowLink = "This is the conference link you need for the next two hours.";
+
+ public static final String printInvalidEvent =
+ "Sorry you have entered an invalid Timetable Command or your input is in the wrong format!\n"
+ + "Please enter a valid Timetable Command or input \"help\" to find out the correct format!\n";
+}
diff --git a/src/main/java/timetable/TablePrinter.java b/src/main/java/timetable/TablePrinter.java
new file mode 100644
index 0000000000..6dda8a677a
--- /dev/null
+++ b/src/main/java/timetable/TablePrinter.java
@@ -0,0 +1,55 @@
+package timetable;
+
+import java.time.LocalDate;
+import java.util.List;
+
+
+public class TablePrinter {
+ private static final String space = " ";
+
+ public static void printTable(List dateList) {
+ String[][] table = new String[8][25];
+ table[0][0] = space;
+ for (int i = 0; i < 2400; i += 100) {
+ table[0][i / 100 + 1] = String.format("%04d", i);
+ }
+
+ for (int i = 0; i < 7; i++) {
+ table[i + 1][0] = LocalDate.now().plusDays(i).getDayOfWeek().name();
+ boolean skip = false;
+ for (int dateListIndex = 0; dateListIndex < dateList.size() && !skip; dateListIndex++) {
+ if (dateList.get(dateListIndex).dateTag.equals(LocalDate.now().plusDays(i))) {
+ for (int j = 0; j < 24; j++) {
+ boolean isFree = true;
+ for (int eventListIndex = 0; eventListIndex < dateList.get(dateListIndex).events.size();
+ eventListIndex++) {
+ Event current = dateList.get(dateListIndex).events.get(eventListIndex);
+ for (Duration period: current.periods) {
+ if (period.containTimeSlot(j * 100) && period.startDateTime
+ .toLocalDate().equals(dateList.get(dateListIndex).dateTag)) {
+ table[i + 1][j + 1] = current.name;
+ isFree = false;
+ }
+ }
+ }
+ if (isFree) {
+ table[i + 1][j + 1] = space;
+ }
+ }
+ skip = true;
+ }
+ }
+ for (int j = 0; j < 24 && !skip; j++) {
+ table[i + 1][j + 1] = space;
+ }
+ }
+
+ for (int i = 0; i < 25; i++) {
+ for (int j = 0; j < 8; j++) {
+ System.out.printf("%-10s|", table[j][i].substring(0, Math.min(table[j][i].length(), 10)));
+ }
+ System.out.println("");
+ }
+ }
+
+}
diff --git a/src/main/java/timetable/TimeTableCommand.java b/src/main/java/timetable/TimeTableCommand.java
new file mode 100644
index 0000000000..062f8d94bc
--- /dev/null
+++ b/src/main/java/timetable/TimeTableCommand.java
@@ -0,0 +1,338 @@
+package timetable;
+
+import exceptions.InvalidDayOfTheWeekException;
+import exceptions.InvalidTimeException;
+
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Scanner;
+
+public class TimeTableCommand {
+ public static Lesson addClass() throws InvalidDayOfTheWeekException, InvalidTimeException {
+ Scanner in = new Scanner(System.in);
+ System.out.println("Please enter module code: ");
+ boolean isInvalid = true;
+ String moduleCode = null;
+ while (isInvalid) {
+ moduleCode = in.nextLine().replace(" ", "");
+ if (moduleCode.length() > 8) {
+ System.out.println("The code exceeded the maximum number of characters allowed. Please enter again: ");
+ } else if (moduleCode.length() < 1) {
+ System.out.println("Please enter a valid module code");
+ } else {
+ isInvalid = false;
+ }
+ }
+ isInvalid = true;
+ System.out.println("Is the class online? (yes/no)");
+ boolean isOnline = false;
+ while (isInvalid) {
+ String status = in.nextLine();
+ if (status.equals("yes") || status.equals("online")) {
+ isOnline = true;
+ System.out.println("Please enter zoom link: ");
+ isInvalid = false;
+ } else if (status.equals("no") || status.equals("offline")) {
+ System.out.println("Please enter the venue: ");
+ isInvalid = false;
+ } else {
+ System.out.println("Invalid command!\n Is the class online? (yes/no)");
+ }
+ }
+ isInvalid = true;
+ String linkOrVenue = null;
+ while (isInvalid) {
+ linkOrVenue = in.nextLine();
+ if (isOnline && (!linkOrVenue.contains(".") || linkOrVenue.contains(" "))) {
+ System.out.println("The link you have entered is invalid. Please enter again");
+ } else {
+ isInvalid = false;
+ }
+ }
+ System.out.println("What are the days and time of the lesson?\n(e.g. Monday 5-8pm, Tuesday 6-9pm)");
+ final String [] periods = in.nextLine().split(", ");
+ isInvalid = true;
+ int repeat = 0;
+ while (isInvalid) {
+ try {
+ System.out.println("How many weeks is the lesson?");
+ repeat = Integer.parseInt(in.nextLine());
+ if (repeat < 54) {
+ isInvalid = false;
+ } else {
+ System.out.println("Your lesson should not last for more than a year "
+ + "Please enter a number less than 53");
+ }
+ } catch (NumberFormatException e) {
+ System.out.println("You have enter an invalid value");
+ }
+ }
+ isInvalid = true;
+ LocalDateTime startDay = null;
+ while (isInvalid) {
+ try {
+ System.out.println("Which date does the lesson start? (eg. 26/10/2020)");
+ startDay = getDate(in.nextLine());
+ isInvalid = false;
+ } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
+ System.out.println("You have entered an invalid date format. Please try again");
+ }
+ }
+ Lesson lesson = new Lesson(moduleCode, linkOrVenue, isOnline, repeat);
+ addClassPeriods(periods, repeat, startDay, lesson);
+ return lesson;
+ }
+
+ public static void addClassPeriods(String[] periods, int repeat, LocalDateTime startDay,
+ Lesson lesson) throws InvalidDayOfTheWeekException, InvalidTimeException {
+ int startDayNum = startDay.getDayOfWeek().getValue();
+ for (int i = 0; i < repeat; i++) {
+ for (String period : periods) {
+ String [] dayAndTime = period.split((" "));
+ String day = dayAndTime[0].toUpperCase().replace(" ", "");
+ String time = dayAndTime[1];
+ int dayNum;
+ try {
+ dayNum = DayOfWeek.valueOf(day).getValue();
+ } catch (IllegalArgumentException e) {
+ throw new InvalidDayOfTheWeekException();
+ }
+ String start;
+ String end;
+ int startTime;
+ int endTime;
+ try {
+ start = time.split("-")[0];
+ end = time.split("-")[1];
+ startTime = Integer.parseInt(start.replaceAll("[^0-9]", ""));
+ endTime = Integer.parseInt(end.replaceAll("[^0-9]", ""));
+ if (start.contains("am") || start.contains("pm")) {
+ if (start.contains("pm") && startTime != 12) {
+ startTime += 12;
+ } else if (start.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ if (end.contains("pm") && startTime != 12) {
+ endTime += 12;
+ } else if (end.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ } else if (end.contains("pm")) {
+ endTime += 12;
+ if (startTime != 12) {
+ startTime += 12;
+ }
+ } else if (end.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ if (startTime >= endTime) {
+ throw new InvalidTimeException();
+ }
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
+ throw new InvalidTimeException();
+ }
+ int daysDifference = dayNum - startDayNum;
+ if (daysDifference < 0) {
+ daysDifference += 7;
+ }
+ LocalDateTime startDateTime = startDay.plusDays(daysDifference).plusHours(startTime).plusDays(7 * i);
+ LocalDateTime endDateTime = startDateTime.withHour(endTime).plusDays(7 * i);
+ Duration duration = new Duration(startDateTime, endDateTime);
+ lesson.addPeriod(duration);
+ }
+ }
+ }
+
+ public static Activity addActivity() {
+ Scanner in = new Scanner(System.in);
+ boolean isInvalid = true;
+ String activityName = null;
+ System.out.println("Please enter the activity: ");
+ while (isInvalid) {
+ activityName = in.nextLine();
+ if (activityName.replace(" ", "").length() < 1) {
+ System.out.println("Please enter a valid activity");
+ } else {
+ isInvalid = false;
+ }
+ }
+ isInvalid = true;
+ System.out.println("Is the activity online? (yes/no)");
+ boolean isOnline = false;
+ while (isInvalid) {
+ String status = in.nextLine();
+ if (status.equals("yes") || status.equals("online")) {
+ isOnline = true;
+ System.out.println("Please enter zoom link: ");
+ isInvalid = false;
+ } else if (status.equals("no") || status.equals("offline")) {
+ System.out.println("Please enter the venue: ");
+ isInvalid = false;
+ } else {
+ System.out.println("Invalid command!\n Is the class online? (yes/no)");
+ }
+ }
+ isInvalid = true;
+ String linkOrVenue = null;
+ while (isInvalid) {
+ linkOrVenue = in.nextLine();
+ if (isOnline && (!linkOrVenue.contains(".") || linkOrVenue.contains(" "))) {
+ System.out.println("The link you have entered is invalid. Please enter again");
+ } else {
+ isInvalid = false;
+ }
+ }
+ isInvalid = true;
+ LocalDateTime date = null;
+ while (isInvalid) {
+ System.out.println("Please enter the date of your activity (e.g. 28/10/2020): ");
+ try {
+ date = getDate(in.nextLine());
+ isInvalid = false;
+ } catch (NumberFormatException | ArrayIndexOutOfBoundsException | DateTimeException e) {
+ System.out.println("You have entered an invalid date format. Please try again");
+ }
+ }
+ isInvalid = true;
+ String start;
+ String end;
+ int startTime;
+ int endTime;
+ LocalDateTime startDateTime = null;
+ LocalDateTime endDateTime = null;
+ while (isInvalid) {
+ System.out.println("Please enter the time of your activity (e.g. 6-9pm): ");
+ String time = in.nextLine();
+ try {
+ start = time.split("-")[0];
+ end = time.split("-")[1];
+ startTime = Integer.parseInt(start.replaceAll("[^0-9]", ""));
+ endTime = Integer.parseInt(end.replaceAll("[^0-9]", ""));
+ if (start.contains("am") || start.contains("pm")) {
+ if (start.contains("pm") && startTime != 12) {
+ startTime += 12;
+ } else if (start.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ if (end.contains("pm") && endTime != 12) {
+ endTime += 12;
+ } else if (end.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ } else if (end.contains("pm")) {
+ endTime += 12;
+ if (startTime != 12) {
+ startTime += 12;
+ }
+ } else if (end.contains("am") && startTime == 12) {
+ startTime = 0;
+ }
+ if (startTime < endTime) {
+ isInvalid = false;
+ startDateTime = date.plusHours(startTime);
+ endDateTime = date.withHour(endTime);
+ } else {
+ System.out.println("You have entered an ending time that is not later than the starting time."
+ + " Please try again ");
+ }
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException | DateTimeException e) {
+ System.out.println("You have entered an invalid time. Please try again");
+ isInvalid = true;
+ }
+ }
+
+ Duration duration = new Duration(startDateTime, endDateTime);
+ return new Activity(activityName, isOnline, linkOrVenue, duration);
+ }
+
+ public static void showLink(DateList dateList) {
+ LocalDate todayDate = LocalDateTime.now().toLocalDate();
+ int now = LocalDateTime.now().toLocalTime().getHour() * 100;
+ for (EventList eventList: dateList.dateList) {
+ if (eventList.dateTag.equals(todayDate)) {
+ accessEventList(eventList, todayDate, now);
+ return;
+ }
+ }
+ }
+
+ public static void accessEventList(EventList eventList, LocalDate todayDate, int now) {
+ boolean exist = false;
+ for (Event event: eventList.events) {
+ for (Duration period: event.periods) {
+ if ((period.timeSlot.contains(now) || period.timeSlot.contains(now + 100)
+ || period.timeSlot.contains(now + 200))
+ && period.startDateTime.toLocalDate().equals(todayDate)) {
+ System.out.print(event.linkOrVenue + " | " + event.name + "\n");
+ exist = true;
+ }
+ }
+ }
+ if (!exist) {
+ System.out.println("You do not have anything scheduled in the next two hours");
+ }
+ }
+
+ public static void showActivities(DateList dateList) {
+ int index = 0;
+ for (Activity activity: dateList.activities) {
+ index++;
+ System.out.println(index + ". " + activity.name + " "
+ + activity.periods.get(0).startDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
+ + (activity.isOnline ? " online link: " : " offline venue: ") + activity.linkOrVenue);
+ }
+ if (index == 0) {
+ System.out.println("There is no activity in the list");
+ }
+ }
+
+ public static void showClass(DateList dateList) {
+ int index = 0;
+ for (Lesson lesson: dateList.lessons) {
+ index++;
+ System.out.print(index + ". " + lesson.name + " ");
+ DayOfWeek first = null;
+ try {
+ first = lesson.periods.get(0).startDateTime.getDayOfWeek();
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println("There is error in saved classes, do you want to reformat the data file?");
+ Scanner in = new Scanner(System.in);
+ if (in.nextLine().equals("yes")) {
+ new TimeTableStorage("data/timetable.txt", dateList).wipeFile();
+ } else {
+ System.out.println("Please edit the data to fix this this.");
+ }
+ return;
+ }
+ int num = 1;
+ System.out.print(first);
+ try {
+ while (first != lesson.periods.get(num).startDateTime.getDayOfWeek()) {
+ System.out.print(", " + lesson.periods.get(num).startDateTime.getDayOfWeek());
+ num++;
+ }
+ System.out.print("\n");
+ } catch (IndexOutOfBoundsException e) {
+ System.out.print("\n");
+ }
+ System.out.println((lesson.isOnline ? " online link:" : " offline venue: ")
+ + lesson.linkOrVenue);
+ }
+ if (index == 0) {
+ System.out.println("There is no classes in the list");
+ }
+ }
+
+ public static LocalDateTime getDate(String date) {
+ String [] dateArray = date.split("/");
+ int day = Integer.parseInt(dateArray[0]);
+ int month = Integer.parseInt(dateArray[1]);
+ int year = Integer.parseInt(dateArray[2]);
+ return LocalDateTime.of(year, month, day, 0, 0);
+ }
+
+
+}
diff --git a/src/main/java/timetable/TimeTableParser.java b/src/main/java/timetable/TimeTableParser.java
new file mode 100644
index 0000000000..782a21a4a6
--- /dev/null
+++ b/src/main/java/timetable/TimeTableParser.java
@@ -0,0 +1,141 @@
+package timetable;
+
+import exceptions.ClashScheduleException;
+import exceptions.InvalidDayOfTheWeekException;
+import exceptions.InvalidTimeException;
+import studyit.StudyItLog;
+
+import java.time.DateTimeException;
+import java.time.LocalDateTime;
+
+public class TimeTableParser {
+ public static void commandParser(String command, DateList dateList, TimeTableStorage storage) {
+ switch (command) {
+ case "show schedule":
+ System.out.println(Message.printShowSchedule);
+ TablePrinter.printTable(dateList.dateList);
+ return;
+ case "show link":
+ System.out.println(Message.printShowLink);
+ TimeTableCommand.showLink(dateList);
+ return;
+ case "list activity":
+ TimeTableCommand.showActivities(dateList);
+ return;
+ case "list class":
+ TimeTableCommand.showClass(dateList);
+ return;
+ case "clean up":
+ dateList.cleanUpEvent(storage);
+ System.out.println("Clean up completed");
+ return;
+ default:
+ String[] words = command.split(" ");
+ if (words.length == 2) {
+ try {
+ String action = words[0];
+ String type = words[1];
+ if (action.equals("add")) {
+ switch (type) {
+ case "activity": {
+ Activity activity = TimeTableCommand.addActivity();
+ dateList.addEvent(activity);
+ dateList.activities.add(activity);
+ storage.writeFile(activity);
+ System.out.println(Message.printSuccessfulActivityAddition);
+ }
+ break;
+ case "class": {
+ Lesson lesson = TimeTableCommand.addClass();
+ dateList.addEvent(lesson);
+ dateList.lessons.add(lesson);
+ storage.writeFile(lesson);
+ System.out.println(Message.printSuccessfulClassAddition);
+ }
+ break;
+ default:
+ System.out.print((Message.printInvalidEvent));
+ }
+ } else {
+ System.out.print(Message.printInvalidEvent);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("Input for days and time of the lesson is invalid. Please add the class again.");
+ StudyItLog.logger.warning("Invalid timetable command: Invalid date input");
+ } catch (InvalidDayOfTheWeekException e) {
+ System.out.println("Day of the week input is invalid. Please add the class again.");
+ StudyItLog.logger.warning("Invalid timetable command: Invalid day of the week input");
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule! Please check your schedule and add again.");
+ } catch (InvalidTimeException | DateTimeException e) {
+ System.out.println("Input for time of the lesson is invalid! Please add class again.");
+ }
+ } else if (command.contains("delete activity") && words.length == 3) {
+ try {
+ int index = Integer.parseInt(words[2]);
+ System.out.println(dateList.activities.get(index - 1).name + " has been deleted");
+ dateList.deleteActivity(index, storage);
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
+ System.out.println(Message.printInvalidEvent);
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println("The number you have entered is invalid.");
+ }
+ } else if (command.contains("delete class") && words.length == 3) {
+ try {
+ int index = Integer.parseInt(words[2]);
+ System.out.println(dateList.lessons.get(index - 1).name + " has been deleted");
+ dateList.deleteLesson(index, storage);
+ } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
+ System.out.println(Message.printInvalidEvent);
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println("The number you have entered is invalid.");
+ }
+ } else {
+ System.out.print(Message.printInvalidEvent);
+ }
+ }
+ }
+
+
+ public static void fileParser(String command, DateList dateList) {
+ String[] words = command.split("\\|");
+ EventType eventType = EventType.valueOf(words[0]);
+ String name = words[1];
+ String linkOrVenue = words[2];
+ boolean isOnline = Boolean.parseBoolean(words[3]);
+ try {
+ switch (eventType) {
+ case L: {
+ int numPerWeek = Integer.parseInt(words[4]);
+ int durationNum = Integer.parseInt(words[5]);
+ Lesson lesson = new Lesson(name, linkOrVenue, isOnline, numPerWeek);
+ for (int i = 0; i < durationNum; i++) {
+ assert words[5 + 2 * i + 1].contains("-") : "this word should be the datetime format";
+ LocalDateTime start = LocalDateTime.parse(words[5 + 2 * i + 1]);
+ assert words[5 + 2 * i + 2].contains("-") : "this word should be the datetime format";
+ LocalDateTime end = LocalDateTime.parse(words[5 + 2 * i + 2]);
+ Duration duration = new Duration(start, end);
+ lesson.addPeriod(duration);
+ }
+ dateList.addEvent(lesson);
+ dateList.lessons.add(lesson);
+ }
+ break;
+ case A: {
+ LocalDateTime start = LocalDateTime.parse(words[4]);
+ LocalDateTime end = LocalDateTime.parse(words[5]);
+ Duration duration = new Duration(start, end);
+ Activity activity = new Activity(name, isOnline, linkOrVenue, duration);
+ dateList.addEvent(activity);
+ dateList.activities.add(activity);
+ }
+ break;
+ default:
+ }
+ } catch (ClashScheduleException e) {
+ System.out.println("There is a clash in schedule!");
+ }
+ }
+
+
+}
diff --git a/src/main/java/timetable/TimeTableRun.java b/src/main/java/timetable/TimeTableRun.java
new file mode 100644
index 0000000000..943ac0a8a4
--- /dev/null
+++ b/src/main/java/timetable/TimeTableRun.java
@@ -0,0 +1,21 @@
+package timetable;
+
+import studyit.StudyItLog;
+
+import java.util.Scanner;
+
+public class TimeTableRun {
+
+ public DateList events;
+ public TimeTableStorage storage;
+
+ public TimeTableRun() {
+ events = new DateList();
+ storage = new TimeTableStorage("data/timetable.txt", events);
+ StudyItLog.logger.info("Academic mode initialized");
+ }
+
+ public void run(String command) {
+ TimeTableParser.commandParser(command, events, storage);
+ }
+}
diff --git a/src/main/java/timetable/TimeTableStorage.java b/src/main/java/timetable/TimeTableStorage.java
new file mode 100644
index 0000000000..1b9d770096
--- /dev/null
+++ b/src/main/java/timetable/TimeTableStorage.java
@@ -0,0 +1,93 @@
+package timetable;
+
+import studyit.StudyItLog;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.format.DateTimeParseException;
+import java.util.Scanner;
+
+public class TimeTableStorage {
+
+ private static File taskFile;
+ private final String filePath;
+
+ public TimeTableStorage(String filePath, DateList dateList) {
+ // Creates data directory
+ String dirPath = "data";
+ File fileDir = new File(dirPath);
+
+ if (!fileDir.exists()) {
+ fileDir.mkdir();
+ }
+
+ this.filePath = filePath;
+ taskFile = new File(filePath);
+ checkFile(dateList);
+ }
+
+ public void checkFile(DateList dateList) {
+ try {
+ if (taskFile.createNewFile()) {
+ System.out.println("data/timetable.txt is not found, creating a new file now!");
+ } else {
+ loadFile(dateList);
+ }
+ } catch (IOException e) {
+ System.out.println("An error occurred: " + e.getMessage());
+ StudyItLog.logger.warning("Problem loading timetable storage file\n" + e);
+ }
+ }
+
+ private void loadFile(DateList dateList) {
+ try {
+ Scanner s = new Scanner(taskFile);
+ while (s.hasNext()) {
+ String command = s.nextLine();
+ TimeTableParser.fileParser(command, dateList);
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("File not found");
+ } catch (ArrayIndexOutOfBoundsException | DateTimeParseException | NumberFormatException e) {
+ Scanner in = new Scanner(System.in);
+ System.out.println("Data file for timetable is corrupted do you want to format the file");
+ if (in.nextLine().equals("yes")) {
+ wipeFile();
+ System.out.println("Data file for timetable have been formatted");
+ } else {
+ System.out.println("Please exit the program and edit timetable.txt "
+ + "manually before using this feature.");
+ }
+ }
+ }
+
+ public void writeFile(Event event) {
+ try {
+ FileWriter fw = new FileWriter(filePath, true);
+ if (event.eventType.equals(EventType.L)) {
+ fw.write("L|" + event.name + "|" + event.linkOrVenue + "|" + event.isOnline
+ + event.getStorageString() + System.lineSeparator());
+ } else if (event.eventType.equals(EventType.A)) {
+ fw.write("A|" + event.name + "|" + event.linkOrVenue + "|" + event.isOnline
+ + event.getStorageString() + System.lineSeparator());
+ }
+ fw.close();
+ } catch (IOException e) {
+ System.out.println("Something went wrong" + e.getMessage());
+ StudyItLog.logger.warning("Problem writing to timetable storage file\n" + e);
+ }
+ }
+
+ public void wipeFile() {
+ try {
+ FileWriter fw = new FileWriter(filePath);
+ fw.write("");
+ fw.close();
+ } catch (IOException e) {
+ System.out.println("Something went wrong" + e.getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/userinterface/ErrorMessage.java b/src/main/java/userinterface/ErrorMessage.java
new file mode 100644
index 0000000000..5eb4339074
--- /dev/null
+++ b/src/main/java/userinterface/ErrorMessage.java
@@ -0,0 +1,45 @@
+package userinterface;
+
+public class ErrorMessage extends Ui {
+
+ public static void printUnidentifiableCommand() {
+ printLine("Sorry that's not an available command! Please try again\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printUnidentifiableInput() {
+ printLine("Sorry that's not an available input! Please try again\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printInvalidNumber() {
+ printLine("Please enter a valid number when applicable!\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printInvalidGrade() {
+ printLine("Please enter a valid grade!\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printInvalidMc() {
+ printLine("MC must be a positive integer!\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printInvalidEmail() {
+ printLine("Please enter a valid email with the structure of abc@xyz!\n"
+ + "or you can type \"help\" for more information");
+ }
+
+ public static void printRepeatedGrade() {
+ printLine("This grade has already been added!");
+ }
+
+ public static void printEmptyInput() {
+ printLine("You cannot leave this input empty!\n"
+ + "or you can type \"help\" for more information");
+ }
+}
+
+
diff --git a/src/main/java/userinterface/HelpMessage.java b/src/main/java/userinterface/HelpMessage.java
new file mode 100644
index 0000000000..e3e3300e95
--- /dev/null
+++ b/src/main/java/userinterface/HelpMessage.java
@@ -0,0 +1,111 @@
+package userinterface;
+
+import studyit.Mode;
+import studyit.StudyIt;
+
+public class HelpMessage extends Ui {
+ private static final String generalCommands = "Here are the general commands available:\n"
+ + "help - prints out help message\n"
+ + "location - tells you your current mode\n"
+ + "cd MODE_INDEX/NAME - changes the program to the corresponding mode\n"
+ + "highlight - prints out the important items you stored\n"
+ + "exit - exit the program/mode you are currently at\n";
+
+ public static final String currentModes = "These are the modes you can go to:\n"
+ + "1 menu\n"
+ + "2 bookmark - bookmark internet links\n"
+ + "3 timetable - plan your study schedule\n"
+ + "4 academic - track your academic details\n"
+ + "5 flashcard - flashcards to revise your study materials\n";
+
+ private static final String academicCommands = "Here are the academic commands available:\n"
+ + "list star - prints the list of starred components\n\n"
+ + "---------CONTACTS--------\n"
+ + "add contact c/CONTACT - adds a contact\n"
+ + " m/MOBILE e/EMAIL\n"
+ + "list contact - prints the list of contact currently stored\n"
+ + "delete contact INDEX_NUMBER - deletes contact at specified index\n"
+ + "star contact INDEX_NUMBER - marks the contact as star\n\n"
+ + "----------GRADE----------\n"
+ + "add grade n/MODULE_NAME - adds a grade\n"
+ + " m/MC g/GRADE\n"
+ + "check cap - prints the current CAP based on grade stored\n"
+ + "list grade - prints the list of grades currently stored\n"
+ + "delete grade INDEX_NUMBER - deletes grade at specified index\n"
+ + "su grade INDEX_NUMBER - SU the grade at specified index\n"
+ + "star grade INDEX_NUMBER - marks the grade as star";
+
+ private static final String bookmarkCommands = "Here are the bookmark commands available:\n"
+ + "bm CATEGORY_INDEX - changes mode from bookmark main into a category \n"
+ + "back - go back to bookmark main\n"
+ + "add LINK - add bookmark link into a specific category\n"
+ + "add LINK t-> TITLE - add optional title to your link!\n"
+ + "cat CATEGORY_NAME - add category to bookmark list\n"
+ + "rm LINK_INDEX - remove a bookmark link into a specific category\n"
+ + "delete CATEGORY_INDEX - remove a bookmark category\n"
+ + "list - prints the list of links in your current mode\n"
+ + "list -s - prints the list of starred bookmarks\n"
+ + "list -c - prints the list of categories available\n"
+ + "list -a - prints the list of categories and\n"
+ + " respective list of links\n"
+ + "star LINK_NUMBER - mark the bookmark link as star";
+
+ private static final String timetableCommands = "Here are the timetable commands available:\n"
+ + "add class - adds a class to the timetable\n"
+ + "add activity - adds an activity to the timetable\n"
+ + "show link - displays the links/venues of events occurring\n"
+ + " in the next 2 hours\n"
+ + "show schedule - displays schedule\n"
+ + "list activity - display the list of activities with its date\n"
+ + "list class - display the list of class with days of the week\n"
+ + "delete activity INDEX_NUMBER - delete the activity at specific index\n"
+ + "delete class INDEX_NUMBER - delete the class at specific index\n"
+ + "clean up - delete all activities that end more than 7 days ago\n"
+ + " and classes that had its last lesson more than 7 days ago";
+
+ private static final String flashcardCommands = "Here are the flashcard commands available:\n"
+ + "add - adds a question and answer to the flashcard deck\n"
+ + "list - shows the flashcards that have been added\n"
+ + "delete - deletes the flashcard corresponding to the card index entered by user\n"
+ + "test - user can attempt to answer a random question from the flashcard deck\n"
+ + " use \"back\" to exit test mode, and \"show answer\" to show the answer to the question\n"
+ + "find - searches and returns flashcards containing user's desired search term\n"
+ + "back - exit test mode and go back to flashcard main";
+
+ public static void printHelpMessage() {
+ System.out.println(LINE_DIVIDER);
+ System.out.println(generalCommands);
+ System.lineSeparator();
+ System.out.println(currentModes);
+ System.lineSeparator();
+
+ Mode currentMode = StudyIt.getCurrentMode();
+ if (currentMode == Mode.BOOKMARK) {
+ printBookmarkHelp();
+ } else if (currentMode == Mode.TIMETABLE) {
+ printTimetableHelp();
+ } else if (currentMode == Mode.ACADEMIC) {
+ printAcademicHelp();
+ } else if (currentMode == Mode.FLASHCARD) {
+ printFlashcardHelp();
+ }
+
+ System.out.println(LINE_DIVIDER);
+ }
+
+ public static void printBookmarkHelp() {
+ System.out.println(bookmarkCommands);
+ }
+
+ public static void printTimetableHelp() {
+ System.out.println(timetableCommands);
+ }
+
+ public static void printAcademicHelp() {
+ System.out.println(academicCommands);
+ }
+
+ public static void printFlashcardHelp() {
+ System.out.println(flashcardCommands);
+ }
+}
diff --git a/src/main/java/userinterface/MainMenu.java b/src/main/java/userinterface/MainMenu.java
new file mode 100644
index 0000000000..e2c6b88c17
--- /dev/null
+++ b/src/main/java/userinterface/MainMenu.java
@@ -0,0 +1,38 @@
+package userinterface;
+
+import userinterface.Ui;
+import java.time.format.DateTimeFormatter;
+import java.time.LocalDateTime;
+
+public class MainMenu extends Ui {
+ private static DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("EEE d MMM yyyy");
+ private static DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("hh:mm a");
+ private static LocalDateTime currentDateTime = LocalDateTime.now();
+ private static String currentDateFormatted = dateFormat.format(currentDateTime);
+ private static String currentTimeFormatted = timeFormat.format(currentDateTime);
+
+ private static final String WELCOME_MESSAGE = LINE_DIVIDER + System.lineSeparator()
+ + "Welcome to Study It! Your personal study assistant!"
+ + "\n\n"
+ + "Today's date: " + currentDateFormatted
+ + "\nThe time now is " + currentTimeFormatted
+ + "\n\n"
+ + "Let's get productive!"
+ + "\n\n"
+ + HelpMessage.currentModes
+ + "\nInsert \"cd MODE_INDEX or MODE_NAME\" to access these modes"
+ + "\nor \"help\" to get the list of available commands\n"
+ + LINE_DIVIDER;
+
+ public static void printWelcome() {
+ System.out.println(WELCOME_MESSAGE);
+ }
+
+ public static void printWelcomeBackMessage() {
+ System.out.println("Welcome back to main menu!"
+ + "\n"
+ + "\nToday's date: " + currentDateFormatted
+ + "\nThe time now is " + currentTimeFormatted);
+ printDivider();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/userinterface/Ui.java b/src/main/java/userinterface/Ui.java
new file mode 100644
index 0000000000..2c872d0bc2
--- /dev/null
+++ b/src/main/java/userinterface/Ui.java
@@ -0,0 +1,134 @@
+package userinterface;
+
+import academic.AcademicRun;
+import academic.AcademicUi;
+import academic.Grade;
+import academic.Person;
+import bookmark.BookmarkUi;
+import bookmark.BookmarkRun;
+import exceptions.InvalidModeException;
+import studyit.ModeNames;
+import studyit.Mode;
+import studyit.CommandParser;
+import studyit.StudyIt;
+import studyit.StudyItLog;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+
+public class Ui {
+ public static final String LINE_DIVIDER = "=============================================================="
+ + "==================";
+
+ public static void printDivider() {
+ System.out.println(LINE_DIVIDER);
+ }
+
+ /**
+ * Receive command input from the user via terminal.
+ *
+ * @return the command input as a String
+ */
+ public static String inputCommand() {
+ String command;
+ Scanner in = new Scanner(System.in);
+ assert in != null : "null is passed in";
+
+ command = in.nextLine();
+ assert command.length() >= 0 : "The length of command should be at least 0";
+
+ return command;
+ }
+
+ /**
+ * Prints text with line divider above and below the text.
+ *
+ * @param text any String type text
+ */
+ public static void printLine(String text) {
+ System.out.println(LINE_DIVIDER + "\n" + text + "\n" + LINE_DIVIDER);
+ }
+
+ public static void printExit() {
+ System.out.println(LINE_DIVIDER + "\nSee you again soon!!!\n" + LINE_DIVIDER);
+ }
+
+ public static void printLocation() {
+ printLine("You are currently at " + ModeNames.getCurrentModeName() + "!");
+ }
+
+ public static void changeModeCommand(String command) {
+ try {
+ Mode newMode = CommandParser.getDestinationMode(command);
+
+ if (newMode != StudyIt.getCurrentMode()) {
+ StudyIt.changeMode(newMode);
+ printLine("Mode changed! You are now at: " + ModeNames.getCurrentModeName());
+ printModeIntro(newMode);
+ } else {
+ printLine("You are already in " + ModeNames.getCurrentModeName() + "!");
+ }
+ } catch (InvalidModeException e) {
+ printLine("Invalid mode name! Please try again.\n"
+ + "You are still at: " + ModeNames.getCurrentModeName());
+ StudyItLog.logger.fine("Cannot understand mode chosen.");
+ }
+ }
+
+ public static void printModeIntro(Mode newMode) {
+ // Prints introduction to the mode (if any)
+ if (newMode == Mode.BOOKMARK) {
+ BookmarkUi.printWelcomeBookmarkMessage();
+ printDivider();
+ } else if (newMode == Mode.ACADEMIC) {
+ printWelcomeAcademicMessage();
+ } else if (newMode == Mode.TIMETABLE) {
+ printWelcomeTimetableMessage();
+ } else if (newMode == Mode.FLASHCARD) {
+ printWelcomeFlashcardMessage();
+ } else if (newMode == Mode.MENU) {
+ MainMenu.printWelcomeBackMessage();
+ }
+ }
+
+ public static void printWelcomeAcademicMessage() {
+ System.out.println("Welcome to academic mode!");
+ System.out.println("\nYou can use this mode to keep track of your grades "
+ + "& important contacts");
+ System.out.println("\nInsert \"help\" to find the list of commands available");
+ printDivider();
+ }
+
+ public static void printWelcomeTimetableMessage() {
+ System.out.println("Welcome to timetable mode!");
+ System.out.println("\nYou can use this mode to schedule your classes & events");
+ System.out.println("\nInsert \"help\" to find the list of commands available");
+ printDivider();
+ }
+
+ public static void printWelcomeFlashcardMessage() {
+ System.out.println("Welcome to flashcard mode!");
+ System.out.println("\nYou can use this mode to create and store flashcards and use them to help");
+ System.out.println("you memorize your study content!");
+ System.out.println("\nInsert \"help\" to find the list of commands available");
+ printDivider();
+ }
+
+ public static void exitMode() {
+ printDivider();
+ System.out.println("Exited " + ModeNames.getCurrentModeName() + "!");
+ StudyIt.changeMode(Mode.MENU); //TODO: Check UI
+ System.out.println("You are now back at: " + ModeNames.getCurrentModeName());
+ printDivider();
+ MainMenu.printWelcomeBackMessage();
+ }
+
+ public static void printHighlight(BookmarkRun bookmarkRun, AcademicRun academicRun) {
+ printDivider();
+ System.out.println("Here are your starred items:");
+ bookmarkRun.run("list -s");
+ System.out.println();
+ academicRun.run("list star");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/AcademicParserTest.java b/src/test/java/AcademicParserTest.java
new file mode 100644
index 0000000000..fa8be2c765
--- /dev/null
+++ b/src/test/java/AcademicParserTest.java
@@ -0,0 +1,150 @@
+
+import academic.AcademicCommandParser;
+import academic.AcademicCommandType;
+import exceptions.InvalidCommandException;
+import exceptions.InvalidGradeException;
+import exceptions.InvalidMcException;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+class AcademicParserTest {
+
+
+ @Test
+ void getCommandType_correctCommandInputs_success() throws InvalidCommandException {
+ AcademicCommandParser parser = new AcademicCommandParser();
+
+ assertEquals(AcademicCommandType.ADD_CONTACT, parser.getAcademicCommandType("add contact"));
+ assertEquals(AcademicCommandType.LIST_CONTACT, parser.getAcademicCommandType("list contact"));
+ assertEquals(AcademicCommandType.ADD_GRADE, parser.getAcademicCommandType("add grade"));
+ assertEquals(AcademicCommandType.CHECK_CAP, parser.getAcademicCommandType("check cap"));
+ assertEquals(AcademicCommandType.LIST_GRADE, parser.getAcademicCommandType("list grade"));
+ assertEquals(AcademicCommandType.LIST_GRADE, parser.getAcademicCommandType("list grade"));
+ assertEquals(AcademicCommandType.DELETE_PERSON, parser.getAcademicCommandType("delete contact"));
+ assertEquals(AcademicCommandType.DELETE_GRADE, parser.getAcademicCommandType("delete grade"));
+ assertEquals(AcademicCommandType.SU_GRADE, parser.getAcademicCommandType("su grade"));
+ assertEquals(AcademicCommandType.STAR_GRADE, parser.getAcademicCommandType("star grade"));
+ assertEquals(AcademicCommandType.STAR_CONTACT, parser.getAcademicCommandType("star contact"));
+ assertEquals(AcademicCommandType.LIST_STAR, parser.getAcademicCommandType("list star"));
+ }
+
+ @Test
+ void getCommandType_incorrectCommandInput_exceptionThrown() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ assertThrows(InvalidCommandException.class, () -> {
+ parser.getAcademicCommandType("what is this command?");
+ });
+ }
+
+ @Test
+ void evaluateInput_incorrectGetContact_exceptionThrown() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ assertThrows(NumberFormatException.class, () -> {
+ parser.getContact("add contact c/Prof Lim m/number81234567 e/E7654321@u.nus.edu");
+ });
+ }
+
+ @Test
+ void evaluateInput_incorrectGetGrade_gradeExceptionThrown() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ assertThrows(InvalidGradeException.class, () -> {
+ parser.getGrade("add grade n/CS2101 m/4 g/A+++");
+ });
+
+ }
+
+ @Test
+ void evaluateInput_incorrectGetGrade_mcExceptionThrown() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ assertThrows(InvalidMcException.class, () -> {
+ parser.getGrade("add grade n/CS2101 m/0 g/A");
+ });
+ }
+
+ @Test
+ void evaluateInput_getContactCommand_parsedCorrectly() throws InvalidCommandException {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "add contact c/Prof Lim m/81234567 e/E7654321@u.nus.edu";
+ final String[] result = parser.getContact(input);
+ final String[] expectedResult = {"Prof Lim","81234567","E7654321@u.nus.edu"};
+ assertArrayEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_getGradeCommand_parsedCorrectly()
+ throws InvalidGradeException, InvalidMcException, InvalidCommandException {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "add grade n/CS2101 m/4 g/A-";
+ final String[] result = parser.getGrade(input);
+ final String[] expectedResult = {"CS2101","4","A-"};
+ assertArrayEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseImportedGrade_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "[G] | CS2101 | 4 | A- | true | true";
+ final String[] result = parser.parseImportedGrade(input);
+ final String[] expectedResult = {"CS2101","4","A-","true","true"};
+ assertArrayEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseImportedPerson_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "[P] | Prof Lim | 81234567 | E7654321@u.nus.edu | false";
+ final String[] result = parser.parseImportedPerson(input);
+ final String[] expectedResult = {"Prof Lim","81234567","E7654321@u.nus.edu","false"};
+ assertArrayEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseDeletePerson_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "delete person 5";
+ final Integer result = parser.parseDeletePerson(input);
+ final Integer expectedResult = 5;
+ assertEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseDeleteGrade_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "delete grade 21";
+ final Integer result = parser.parseDeleteGrade(input);
+ final Integer expectedResult = 21;
+ assertEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseSuGrade_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "su grade 1";
+ final Integer result = parser.parseSuGrade(input);
+ final Integer expectedResult = 1;
+ assertEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseStarGrade_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "star grade 2";
+ final Integer result = parser.parseStarGrade(input);
+ final Integer expectedResult = 2;
+ assertEquals(expectedResult,result);
+ }
+
+ @Test
+ void evaluateInput_parseStarContact_parsedCorrectly() {
+ AcademicCommandParser parser = new AcademicCommandParser();
+ String input = "star contact 3";
+ final Integer result = parser.parseStarContact(input);
+ final Integer expectedResult = 3;
+ assertEquals(expectedResult,result);
+ }
+}
diff --git a/src/test/java/CommandParserTest.java b/src/test/java/CommandParserTest.java
new file mode 100644
index 0000000000..ff7164f58e
--- /dev/null
+++ b/src/test/java/CommandParserTest.java
@@ -0,0 +1,82 @@
+import exceptions.InvalidModeException;
+import org.junit.jupiter.api.Test;
+import studyit.CommandParser;
+import studyit.CommandType;
+import studyit.Mode;
+import studyit.StudyIt;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class CommandParserTest {
+
+ @Test
+ void testStandardizeCommand() {
+ CommandParser commandParser = new CommandParser();
+ assertEquals("this is a test", commandParser.standardizeCommand(" ThIs is A teST "));
+ }
+
+ @Test
+ void getCommandType_correctCommandInputs_success() {
+ CommandParser commandParser = new CommandParser();
+
+ // Checks if exit detects correctly when it is in main menu
+ assertEquals(CommandType.EXIT_PROGRAM, commandParser.getCommandType("exit"));
+ assertEquals(CommandType.LOCATION, commandParser.getCommandType("location"));
+ assertEquals(CommandType.CHANGE_MODE, commandParser.getCommandType("cd 3"));
+ assertEquals(CommandType.HELP, commandParser.getCommandType("help"));
+ assertEquals(CommandType.HIGHLIGHT, commandParser.getCommandType("highlight"));
+
+ // Checks if exit detects exit mode when inside one of the modes
+ StudyIt studyIt = new StudyIt();
+ studyIt.changeMode(Mode.ACADEMIC);
+ assertEquals(CommandType.EXIT_MODE, commandParser.getCommandType("exit"));
+ }
+
+ @Test
+ void getCommandType_incorrectCommandInput_unidentifiableCommandType() {
+ CommandParser commandParser = new CommandParser();
+
+ assertEquals(CommandType.UNIDENTIFIABLE, commandParser.getCommandType("asdhajskd"));
+ assertEquals(CommandType.UNIDENTIFIABLE, commandParser.getCommandType("highlight 50000"));
+ assertEquals(CommandType.UNIDENTIFIABLE, commandParser.getCommandType("help test"));
+ assertEquals(CommandType.UNIDENTIFIABLE, commandParser.getCommandType("location wrong"));
+ }
+
+ @Test
+ void getDestinationMode_correctModeInputs_success() throws Exception {
+ CommandParser commandParser = new CommandParser();
+
+ // Test for mode index input
+ assertEquals(Mode.MENU, commandParser.getDestinationMode("cd 1"));
+ assertEquals(Mode.BOOKMARK, commandParser.getDestinationMode("cd 2"));
+ assertEquals(Mode.TIMETABLE, commandParser.getDestinationMode("cd 3"));
+ assertEquals(Mode.ACADEMIC, commandParser.getDestinationMode("cd 4"));
+ assertEquals(Mode.FLASHCARD, commandParser.getDestinationMode("cd 5"));
+
+ // Test for mode name input
+ assertEquals(Mode.MENU, commandParser.getDestinationMode("cd menu"));
+ assertEquals(Mode.BOOKMARK, commandParser.getDestinationMode("cd bookmark"));
+ assertEquals(Mode.TIMETABLE, commandParser.getDestinationMode("cd timetable"));
+ assertEquals(Mode.ACADEMIC, commandParser.getDestinationMode("cd academic"));
+ assertEquals(Mode.FLASHCARD, commandParser.getDestinationMode("cd flashcard"));
+ }
+
+ @Test
+ void getDestinationMode_incorrectModeNumber_exceptionThrown() {
+ CommandParser commandParser = new CommandParser();
+
+ assertThrows(InvalidModeException.class, () -> {
+ commandParser.getDestinationMode("cd 10");
+ });
+ }
+
+ @Test
+ void getDestinationMode_incorrectModeName_exceptionThrown() {
+ CommandParser commandParser = new CommandParser();
+
+ assertThrows(InvalidModeException.class, () -> {
+ commandParser.getDestinationMode("cd easyA");
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/academic/GradeBookTest.java b/src/test/java/academic/GradeBookTest.java
new file mode 100644
index 0000000000..aa09c6d315
--- /dev/null
+++ b/src/test/java/academic/GradeBookTest.java
@@ -0,0 +1,58 @@
+package academic;
+
+import exceptions.EmptyInputException;
+import exceptions.RepeatedGradeException;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+class GradeBookTest {
+ private GradeBook gradeBook = new GradeBook();
+ private ArrayList currentGrade = new ArrayList<>();
+ private Grade testGrade = new Grade("CS2101",4,"A-");
+
+
+
+ @Test
+ void evaluateInput_addGrade_success() throws RepeatedGradeException, EmptyInputException {
+ String[] inputVars = {"CS2101","4","A-","false","false"};
+ gradeBook.addGrade(inputVars,currentGrade);
+ assertEquals(Grade.printIndividualGrade(testGrade),Grade.printIndividualGrade(currentGrade.get(0)));
+ }
+
+ @Test
+ void evaluateInput_printCap_success() throws RepeatedGradeException, EmptyInputException {
+ String[] inputVars = {"CS2101","4","A-","false","false"};
+ gradeBook.addGrade(inputVars,currentGrade);
+ String result = gradeBook.printCap(currentGrade);
+ assertEquals("Current CAP is 4.5.",result);
+ }
+
+ @Test
+ void evaluateInput_printListOfGrades_success() throws RepeatedGradeException, EmptyInputException {
+ String[] inputVars = {"CS2101","4","A-","false","false"};
+ gradeBook.addGrade(inputVars,currentGrade);
+ String result = gradeBook.printListOfGrades(currentGrade);
+ assertEquals("1.[CS2101] [4MC] [A-]",result);
+ }
+
+ @Test
+ void evaluateInput_combineGradeDetails_success() {
+ String result = gradeBook.combineGradeDetails(testGrade);
+ assertEquals("[CS2101] [4MC] [A-]",result);
+ }
+
+ @Test
+ void evaluateInput_deleteGrade_success() throws RepeatedGradeException, EmptyInputException {
+ String[] inputVars = {"CS2101","4","A-","false","false"};
+ gradeBook.addGrade(inputVars,currentGrade);
+ gradeBook.deleteGrade(1,currentGrade);
+ assertTrue(currentGrade.size() == 0);
+ }
+
+}
+
diff --git a/src/test/java/academic/PersonBookTest.java b/src/test/java/academic/PersonBookTest.java
new file mode 100644
index 0000000000..63f4f9b276
--- /dev/null
+++ b/src/test/java/academic/PersonBookTest.java
@@ -0,0 +1,62 @@
+package academic;
+
+import exceptions.EmptyInputException;
+import exceptions.InvalidEmailException;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+class PersonBookTest {
+ private PersonBook personBook = new PersonBook();
+ private ArrayList listOfPerson = new ArrayList<>();
+ private Person testPerson = new Person("Prof Lim", "81234567", "E7654321@u.nus.edu");
+
+
+ @Test
+ void evaluateInput_addPerson_success() throws InvalidEmailException, EmptyInputException {
+ String[] inputVars = {"Prof Lim","81234567","E7654321@u.nus.edu","false"};
+ personBook.addPerson(inputVars,listOfPerson);
+ assertEquals(Person.printIndividualPerson(testPerson),Person.printIndividualPerson(listOfPerson.get(0)));
+ }
+
+ @Test
+ void evaluateInput_incorrectAddPerson_invalidEmailExceptionThrown() {
+ String[] inputVars = {"Prof Lim","81234567","thisIsAEmail","false"};
+ assertThrows(InvalidEmailException.class, () -> {
+ personBook.addPerson(inputVars,listOfPerson);
+ });
+ }
+
+ @Test
+ void evaluateInput_printPersonBook_success() throws InvalidEmailException, EmptyInputException {
+ String[] inputVars = {"Prof Lim","81234567","E7654321@u.nus.edu","false"};
+ personBook.addPerson(inputVars,listOfPerson);
+ String result = personBook.printPersonBook(listOfPerson);
+ assertEquals("1.[Prof Lim] [81234567] [E7654321@u.nus.edu]",result);
+ }
+
+ @Test
+ void evaluateInput_combinePersonDetails_success() {
+ String result = personBook.combinePersonDetails(testPerson);
+ assertEquals("[Prof Lim] [81234567] [E7654321@u.nus.edu]",result);
+ }
+
+ @Test
+ void evaluateInput_deletePerson_success() throws InvalidEmailException, EmptyInputException {
+ String[] inputVars = {"Prof Lim","81234567","E7654321@u.nus.edu","false"};
+ personBook.addPerson(inputVars,listOfPerson);
+ personBook.deletePerson(1,listOfPerson);
+ assertTrue(listOfPerson.size() == 0);
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/BookmarkParserTest.java b/src/test/java/bookmark/BookmarkParserTest.java
new file mode 100644
index 0000000000..3b5d25dabd
--- /dev/null
+++ b/src/test/java/bookmark/BookmarkParserTest.java
@@ -0,0 +1,78 @@
+package bookmark;
+
+import bookmark.BookmarkParser;
+import bookmark.commands.AddLinkCommand;
+import bookmark.commands.BackCommand;
+import bookmark.commands.ChangeModeCommand;
+import bookmark.commands.ListCommand;
+import bookmark.commands.RemoveLinkCommand;
+import bookmark.commands.BookmarkCommand;
+
+import exceptions.InvalidCommandException;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+class BookmarkParserTest {
+ private int chosenCategory;
+
+ @Test
+ void evaluateInput_listCommand_parsedCorrectly() throws InvalidCommandException {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "list";
+ final BookmarkCommand result = parser.evaluateInput(input,chosenCategory);
+ assertTrue(result.getClass().isAssignableFrom(ListCommand.class));
+ }
+
+ @Test
+ void evaluateInput_changeModeCommand_parsedCorrectly() throws InvalidCommandException {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "bm 2";
+ final BookmarkCommand result = parser.evaluateInput(input,chosenCategory);
+ assertTrue(result.getClass().isAssignableFrom(ChangeModeCommand.class));
+ }
+
+ @Test
+ void evaluateInput_addCommand_parsedCorrectly() throws InvalidCommandException {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "add http://facebook.com";
+ final BookmarkCommand result = parser.evaluateInput(input,chosenCategory);
+ assertTrue(result.getClass().isAssignableFrom(AddLinkCommand.class));
+ }
+
+ @Test
+ void evaluateInput_removeCommand_parsedCorrectly() throws InvalidCommandException {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "rm 2";
+ final BookmarkCommand result = parser.evaluateInput(input,chosenCategory);
+ assertTrue(result.getClass().isAssignableFrom(RemoveLinkCommand.class));
+ }
+
+ @Test
+ void evaluateInput_backCommand_parsedCorrectly() throws InvalidCommandException {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "back";
+ final BookmarkCommand result = parser.evaluateInput(input,chosenCategory);
+ assertTrue(result.getClass().isAssignableFrom(BackCommand.class));
+ }
+
+ @Test
+ void evaluateInput_invalidBookmarkCommand_expectExceptions() {
+ BookmarkParser parser = new BookmarkParser();
+ String input = "huhuhuh";
+ assertThrows(InvalidCommandException.class, () -> {
+ parser.evaluateInput(input,chosenCategory);
+ });
+ }
+
+ @Test
+ void evaluateInput_nullCommand_expectExceptions() {
+ BookmarkParser parser = new BookmarkParser();
+ String input = null;
+ assertThrows(InvalidCommandException.class, () -> {
+ parser.evaluateInput(input,chosenCategory);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/AddCategoryCommandTest.java b/src/test/java/bookmark/commands/AddCategoryCommandTest.java
new file mode 100644
index 0000000000..686fd3d79d
--- /dev/null
+++ b/src/test/java/bookmark/commands/AddCategoryCommandTest.java
@@ -0,0 +1,44 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AddCategoryCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ public void executeCommand_addValidCategory_addCategoryCorrectly() {
+ String inputString = "cat Entertainment";
+ int categoryNumber = 0;
+ AddCategoryCommand command = new AddCategoryCommand(inputString, categoryNumber);
+ command.executeCommand(ui, categories, storage);
+ assertEquals(1, categories.size());
+ }
+
+ @Test
+ public void executeCommand_addCategoryInAnotherMode_addCategoryCorrectly() {
+ String inputString = "cat Entertainment";
+ int categoryNumber = 2;
+ AddCategoryCommand command = new AddCategoryCommand(inputString, categoryNumber);
+ command.executeCommand(ui, categories, storage);
+ assertEquals(1, categories.size());
+ }
+
+ @Test
+ public void executeCommand_addEmptyCategoryCommand_doesNotAddCategory() {
+ String inputString = "cat ";
+ int categoryNumber = 0;
+ AddCategoryCommand command = new AddCategoryCommand(inputString, categoryNumber);
+ command.executeCommand(ui, categories, storage);
+ assertEquals(0, categories.size());
+ }
+}
diff --git a/src/test/java/bookmark/commands/AddLinkCommandTest.java b/src/test/java/bookmark/commands/AddLinkCommandTest.java
new file mode 100644
index 0000000000..7a6f539466
--- /dev/null
+++ b/src/test/java/bookmark/commands/AddLinkCommandTest.java
@@ -0,0 +1,92 @@
+package bookmark.commands;
+
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import bookmark.BookmarkCategory;
+
+
+
+import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AddLinkCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ public void executeCommand_addValidLinkCommand_addLinkCorrectly() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add https://facebook.com";
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_addInValidLinkCommand_doesNotAddLink() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add huhuhuh";
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_addEmptyLinkCommand_doesNotAddLink() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add ";
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_categoryNotChosen_doesNotAddLink() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add ";
+ int categoryNumber = 0;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber).getLinks().size());
+ assertEquals(0,categories.get(categoryNumber + 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_validLinkWithTitle_addLinkCorrectly() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add https://facebook.com t->Social Media";;
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_validLinkWithEmptyTitle_doesNotAddLink() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String inputString = "add https://facebook.com t->";;
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/BackCommandTest.java b/src/test/java/bookmark/commands/BackCommandTest.java
new file mode 100644
index 0000000000..f98b8755e7
--- /dev/null
+++ b/src/test/java/bookmark/commands/BackCommandTest.java
@@ -0,0 +1,35 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BackCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ void executeCommand_backCommandInMain_showByeMessage() {
+ int categoryNumber = 0;
+ String input = "back";
+ BackCommand command = new BackCommand(input, categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,command.getCategoryNumber());
+ }
+
+ @Test
+ void executeCommand_backCommandInCategory_returnToBookmarkMain() {
+ int categoryNumber = 1;
+ String input = "back";
+ BackCommand command = new BackCommand(input,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,command.getCategoryNumber());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/ChangeModeCommandTest.java b/src/test/java/bookmark/commands/ChangeModeCommandTest.java
new file mode 100644
index 0000000000..2e27324525
--- /dev/null
+++ b/src/test/java/bookmark/commands/ChangeModeCommandTest.java
@@ -0,0 +1,60 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ChangeModeCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+ @Test
+ void executeCommand_validCategory_returnsUpdatedCategoryNumber() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ int categoryNumber = 0;
+ String inputString = "bm 2";
+ ChangeModeCommand command = new ChangeModeCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(2,command.getCategoryNumber());
+ }
+
+ @Test
+ void executeCommand_InvalidCategory_doesNotUpdateCategoryNumber() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ int categoryNumber = 0;
+ String inputString = "bm 200";
+ ChangeModeCommand command = new ChangeModeCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,command.getCategoryNumber());
+ }
+
+ @Test
+ void executeCommand_EmptyCategory_doesNotUpdateCategoryNumber() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ int categoryNumber = 0;
+ String inputString = "bm ";
+ ChangeModeCommand command = new ChangeModeCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(0,command.getCategoryNumber());
+ }
+
+ @Test
+ void executeCommand_SameCategory_doesNotUpdateCategoryNumber() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ int categoryNumber = 2;
+ String inputString = "bm 2";
+ ChangeModeCommand command = new ChangeModeCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertEquals(2,command.getCategoryNumber());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/RemoveCategoryCommandTest.java b/src/test/java/bookmark/commands/RemoveCategoryCommandTest.java
new file mode 100644
index 0000000000..284fa5d830
--- /dev/null
+++ b/src/test/java/bookmark/commands/RemoveCategoryCommandTest.java
@@ -0,0 +1,72 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class RemoveCategoryCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ void executeCommand_deleteValidCategory_deleteCategoryCorrectly() {
+ setUpBookmark();
+ String inputString = "delete 1";
+ int categoryNumber = 0;
+ RemoveCategoryCommand removeCommand = new RemoveCategoryCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.size());
+ }
+
+ @Test
+ void executeCommand_deleteInValidCategoryCommand_doseNotDeleteCategory() {
+ setUpBookmark();
+ String inputString = "delete 10000"; //rm 0
+ int categoryNumber = 0;
+ RemoveCategoryCommand removeCommand = new RemoveCategoryCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.size());
+ }
+
+ @Test
+ void executeCommand_deleteEmptyCategoryCommand_doesNotDeleteCategory() {
+ setUpBookmark();
+ String inputString = "delete ";
+ int categoryNumber = 0;
+ RemoveCategoryCommand removeCommand = new RemoveCategoryCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.size());
+ }
+
+ @Test
+ void executeCommand_deleteNotANumber_doesNotDeleteCategory() {
+ setUpBookmark();
+ String inputString = "delete abcdef";
+ int categoryNumber = 0;
+ RemoveCategoryCommand removeCommand = new RemoveCategoryCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.size());
+ }
+
+ @Test
+ public void executeCommand_deleteInWrongMode_doesNotDeleteCategory() {
+ setUpBookmark();
+ String inputString = "delete 1";
+ int categoryNumber = 2;
+ RemoveCategoryCommand removeCommand = new RemoveCategoryCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.size());
+ }
+
+ private void setUpBookmark() {
+ categories.add(new BookmarkCategory("NUS"));
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/RemoveLinkCommandTest.java b/src/test/java/bookmark/commands/RemoveLinkCommandTest.java
new file mode 100644
index 0000000000..04a21c5679
--- /dev/null
+++ b/src/test/java/bookmark/commands/RemoveLinkCommandTest.java
@@ -0,0 +1,76 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class RemoveLinkCommandTest {
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ void executeCommand_removeValidLinkCommand_removeLinkCorrectly() {
+ setUpBookmark();
+ String inputString = "rm 1";
+ int categoryNumber = 2;
+ RemoveLinkCommand removeCommand = new RemoveLinkCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ void executeCommand_removeInValidCategoryCommand_doseNotRemoveLink() {
+ setUpBookmark();
+ String inputString = "rm 10000"; //rm 0
+ int categoryNumber = 2;
+ RemoveLinkCommand removeCommand = new RemoveLinkCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ void executeCommand_removeEmptyCategoryCommand_doesNotRemoveLink() {
+ setUpBookmark();
+ String inputString = "rm ";
+ int categoryNumber = 2;
+ RemoveLinkCommand removeCommand = new RemoveLinkCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ void executeCommand_removeNotANumber_doesNotRemoveLink() {
+ setUpBookmark();
+ String inputString = "rm abcdef";
+ int categoryNumber = 2;
+ RemoveLinkCommand removeCommand = new RemoveLinkCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(1,categories.get(categoryNumber - 1).getLinks().size());
+ }
+
+ @Test
+ public void executeCommand_categoryNotChosen_doesNotRemoveLink() {
+ setUpBookmark();
+ String inputString = "rm 1";
+ int categoryNumber = 0;
+ RemoveLinkCommand removeCommand = new RemoveLinkCommand(inputString,categoryNumber);
+ removeCommand.executeCommand(ui,categories,storage);
+ assertEquals(0,categories.get(categoryNumber).getLinks().size());
+ assertEquals(1,categories.get(categoryNumber + 1).getLinks().size());
+ }
+
+ private void setUpBookmark() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.add(new BookmarkCategory("Zoom"));
+ String addLink = "add https://huhuhu.com";
+ int categoryNumber = 2;
+ AddLinkCommand command = new AddLinkCommand(addLink,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/bookmark/commands/StarCommandTest.java b/src/test/java/bookmark/commands/StarCommandTest.java
new file mode 100644
index 0000000000..66caf6462e
--- /dev/null
+++ b/src/test/java/bookmark/commands/StarCommandTest.java
@@ -0,0 +1,74 @@
+package bookmark.commands;
+
+import bookmark.BookmarkCategory;
+import bookmark.BookmarkStorage;
+import bookmark.BookmarkUi;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+class StarCommandTest {
+
+ private BookmarkUi ui = new BookmarkUi();
+ private ArrayList categories = new ArrayList<>();
+ private BookmarkStorage storage = new BookmarkStorage("data/bookmark.txt");
+
+
+ @Test
+ void executeCommand_validStarCommand_markLinkAsStar() {
+ setUp();
+ int categoryNumber = 1;
+ String inputString = "star 1";
+ StarCommand command = new StarCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertTrue(categories.get(0).getLinks().get(0).getStar());
+ }
+
+ @Test
+ void executeCommand_InvalidStarCommand_doesNotMarkLinkAsStar() {
+ setUp();
+ int categoryNumber = 1;
+ String inputString = "star 1000";
+ StarCommand command = new StarCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertFalse(categories.get(0).getLinks().get(0).getStar());
+ }
+
+ @Test
+ void executeCommand_EmptyStarCommand_doesNotMarkLinkAsStar() {
+ setUp();
+ int categoryNumber = 1;
+ String inputString = "star ";
+ StarCommand command = new StarCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertFalse(categories.get(0).getLinks().get(0).getStar());
+ }
+
+ @Test
+ void executeCommand_notANumberStarCommand_doesNotMarkLinkAsStar() {
+ setUp();
+ int categoryNumber = 1;
+ String inputString = "star adhuhu";
+ StarCommand command = new StarCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertFalse(categories.get(0).getLinks().get(0).getStar());
+ }
+
+ @Test
+ void executeCommand_categoryNotChosenStarCommand_doesNotMarkLinkAsStar() {
+ setUp();
+ int categoryNumber = 0;
+ String inputString = "star 1";
+ StarCommand command = new StarCommand(inputString,categoryNumber);
+ command.executeCommand(ui,categories,storage);
+ assertFalse(categories.get(0).getLinks().get(0).getStar());
+ }
+
+ void setUp() {
+ categories.add(new BookmarkCategory("NUS"));
+ categories.get(0).addLink("https://huhu.com", null);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/flashcard/FlashcardDeckTest.java b/src/test/java/flashcard/FlashcardDeckTest.java
new file mode 100644
index 0000000000..21095d7fbf
--- /dev/null
+++ b/src/test/java/flashcard/FlashcardDeckTest.java
@@ -0,0 +1,44 @@
+package flashcard;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class FlashcardDeckTest {
+
+ @Test
+ void executeCommand_addCardsCommand_addCardCorrectly() {
+ FlashcardDeck flashcardDeck = new FlashcardDeck();
+ String input = "2+2\n4\n";
+ InputStream in = new ByteArrayInputStream(input.getBytes());
+ System.setIn(in);
+ flashcardDeck.addCards();
+ assertEquals("2+2", flashcardDeck.flashcardDeck.get(0).question);
+ assertEquals("4", flashcardDeck.flashcardDeck.get(0).answer);
+ }
+
+ @Test
+ void executeCommand_deleteCardCommand_deleteCardCorrectly() {
+ FlashcardDeck flashcardDeck = new FlashcardDeck();
+ Flashcard flashcard1 = new Flashcard("1+1", "2");
+ Flashcard flashcard2 = new Flashcard("2+2", "4");
+ Flashcard flashcard3 = new Flashcard("3+3", "6");
+ Flashcard flashcard4 = new Flashcard("4+4", "8");
+ flashcardDeck.flashcardDeck.add(flashcard1);
+ flashcardDeck.flashcardDeck.add(flashcard2);
+ flashcardDeck.flashcardDeck.add(flashcard3);
+ flashcardDeck.flashcardDeck.add(flashcard4);
+ String input = "3\n";
+ InputStream in = new ByteArrayInputStream(input.getBytes());
+ System.setIn(in);
+ assertEquals(4, flashcardDeck.flashcardDeck.size());
+ flashcardDeck.deleteCard();
+ assertEquals(3, flashcardDeck.flashcardDeck.size());
+ assertEquals("4+4", flashcardDeck.flashcardDeck.get(2).question);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/flashcard/FlashcardTest.java b/src/test/java/flashcard/FlashcardTest.java
new file mode 100644
index 0000000000..6016b0ef00
--- /dev/null
+++ b/src/test/java/flashcard/FlashcardTest.java
@@ -0,0 +1,16 @@
+package flashcard;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class FlashcardTest {
+
+ @Test
+ void writeToFile_addCards_savedToFile() {
+ Flashcard flashcard = new Flashcard("2+2", "4");
+ String expected = "2+2|4\n";
+ String actual = flashcard.writeToFile();
+ assertEquals(expected, actual);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/timetable/DateListTest.java b/src/test/java/timetable/DateListTest.java
new file mode 100644
index 0000000000..e64abb5879
--- /dev/null
+++ b/src/test/java/timetable/DateListTest.java
@@ -0,0 +1,45 @@
+package timetable;
+
+import exceptions.ClashScheduleException;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DateListTest {
+
+ @Test
+ void addLesson_checkListValue() throws ClashScheduleException {
+ DateList dateList = new DateList();
+ Lesson lesson = new Lesson("CS2113", "www.zoom.com/abcde", true, 1);
+ Duration duration1 = new Duration(LocalDateTime.of(2020,10,16,16,0),
+ LocalDateTime.of(2020,10,16,18,0));
+ lesson.addPeriod(duration1);
+ Duration duration2 = new Duration(LocalDateTime.of(2020,10,19,16,0),
+ LocalDateTime.of(2020,10,19,18,0));
+ lesson.addPeriod(duration2);
+ LocalDate result1 = LocalDate.of(2020,10,16);
+ LocalDate result2 = LocalDate.of(2020,10,19);
+ dateList.addEvent(lesson);
+ assertEquals(result1, dateList.dateList.get(0).dateTag);
+ assertEquals(result2, dateList.dateList.get(1).dateTag);
+ }
+
+ @Test
+ void addLesson_addTwoLesson() throws ClashScheduleException {
+ Lesson lesson1 = new Lesson("CS2113", "www.zoom.com/abcde", true, 1);
+ Lesson lesson2 = new Lesson("CS2101", "www.zoom.com/cdefg", true, 1);
+ Duration duration1 = new Duration(LocalDateTime.of(2020,10,16,16,0),
+ LocalDateTime.of(2020,10,16,18,0));
+ lesson1.addPeriod(duration1);
+ Duration duration2 = new Duration(LocalDateTime.of(2020,10,19,16,0),
+ LocalDateTime.of(2020,10,19,18,0));
+ lesson2.addPeriod(duration2);
+ DateList dateList = new DateList();
+ dateList.addEvent(lesson1);
+ dateList.addEvent(lesson2);
+ assertEquals("CS2101", dateList.dateList.get(1).events.get(0).name);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/timetable/DurationTest.java b/src/test/java/timetable/DurationTest.java
new file mode 100644
index 0000000000..bb946ec7fa
--- /dev/null
+++ b/src/test/java/timetable/DurationTest.java
@@ -0,0 +1,31 @@
+package timetable;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class DurationTest {
+
+ private static final LocalDateTime dateTime1 = LocalDateTime.of(2020, 10,16,16,0);
+ private static final LocalDateTime dateTime2 = LocalDateTime.of(2020,10,16,18,0);
+ private static final Duration duration = new Duration(dateTime1, dateTime2);
+
+ @Test
+ void getTime() {
+ assertEquals(1600, duration.getTime(dateTime1));
+ }
+
+ @Test
+ void containTimeSlot_testTrue() {
+ assertTrue(duration.containTimeSlot(1700));
+ }
+
+ @Test
+ void containTimeSlot_testFalse() {
+ assertFalse(duration.containTimeSlot(1300));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/timetable/LessonTest.java b/src/test/java/timetable/LessonTest.java
new file mode 100644
index 0000000000..4e6094dd77
--- /dev/null
+++ b/src/test/java/timetable/LessonTest.java
@@ -0,0 +1,20 @@
+package timetable;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class LessonTest {
+
+ @Test
+ void getStorageString_test() {
+ Lesson lesson = new Lesson("CS2113", "www.zoom.com/abcde", true, 1);
+ Duration duration = new Duration(LocalDateTime.of(2020,10,16,16,0),
+ LocalDateTime.of(2020,10,16,18,0));
+ lesson.addPeriod(duration);
+ assertEquals("|1|1|2020-10-16T16:00|2020-10-16T18:00",
+ lesson.getStorageString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/timetable/TimeTableParserTest.java b/src/test/java/timetable/TimeTableParserTest.java
new file mode 100644
index 0000000000..9861705f7f
--- /dev/null
+++ b/src/test/java/timetable/TimeTableParserTest.java
@@ -0,0 +1,71 @@
+package timetable;
+
+import exceptions.ClashScheduleException;
+import exceptions.InvalidDayOfTheWeekException;
+import exceptions.InvalidTimeException;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class TimeTableParserTest {
+
+
+ @Test
+ void addClassTest() throws InvalidDayOfTheWeekException, InvalidTimeException {
+ String input = "CS1234\n" + "yes\n" + "www.zoom.com/asdf\n"
+ + "Wednesday 2-4pm\n" + "1\n" + "20/10/2020\n";
+ InputStream in = new ByteArrayInputStream(input.getBytes());
+ System.setIn(in);
+ Lesson lesson = TimeTableCommand.addClass();
+ Duration duration = new Duration(LocalDateTime.of(2020,10,21,14,0),
+ LocalDateTime.of(2020,10,21,16,0));
+ List expectedPeriod = new ArrayList<>();
+ expectedPeriod.add(duration);
+ assertEquals("CS1234", lesson.name);
+ assertEquals(EventType.L, lesson.eventType);
+ assertEquals(expectedPeriod.get(0).timeSlot, lesson.periods.get(0).timeSlot);
+ }
+
+ @Test
+ void addClassTest_throwInvalidDayOfWeekException() {
+ String input = "CS1234\n" + "yes\n" + "www.zoom.com/asdf\n"
+ + "Wednfesday 2-4pm\n" + "1\n" + "20/10/2020\n";
+ InputStream in = new ByteArrayInputStream(input.getBytes());
+ System.setIn(in);
+ assertThrows(InvalidDayOfTheWeekException.class, TimeTableCommand::addClass);
+ }
+
+
+ @Test
+ void showLinkTest() throws InvalidDayOfTheWeekException, ClashScheduleException, InvalidTimeException {
+ DateList dateList = new DateList();
+ int currentHour = LocalDateTime.now().getHour();
+ String currentDay = LocalDateTime.now().getDayOfWeek().toString();
+ Lesson lesson1 = new Lesson("CS1234", "www.zoom.com/asdf", true, 1);
+ Lesson lesson2 = new Lesson("CS5678", "www.zoom.com/qwer", true, 1);
+ if (currentHour < 22) {
+ String periodText1 = currentDay + " " + (currentHour) + "-" + (currentHour + 1);
+ String[] period1 = periodText1.split(", ");
+ String periodText2 = currentDay + " " + (currentHour + 1) + "-" + (currentHour + 2);
+ String[] period2 = periodText2.split(", ");
+ TimeTableCommand.addClassPeriods(period1, 1, LocalDateTime.now().toLocalDate().atTime(0, 0), lesson1);
+ TimeTableCommand.addClassPeriods(period2, 1, LocalDateTime.now().toLocalDate().atTime(0, 0), lesson2);
+ dateList.addEvent(lesson1);
+ dateList.addEvent(lesson2);
+ ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(outContent));
+ TimeTableCommand.showLink(dateList);
+ String expected = "www.zoom.com/asdf | CS1234\nwww.zoom.com/qwer | CS5678\n";
+ assertEquals(expected, outContent.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..e69de29bb2 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +0,0 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..e69de29bb2 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +0,0 @@
-James Gosling
\ No newline at end of file