By: Team Plan²travel      Since: Sep 2019      Licence: MIT
- 1. Setting up
- 2. Design
- 3. Implementation
- 4. Documentation
- 5. Testing
- 6. Dev Ops
- Appendix A: Product Scope
- Appendix B: User Stories
- Appendix C: Use Cases
- Appendix D: Non Functional Requirements
- Appendix E: Glossary
- Appendix F: Instructions for Manual Testing
- F.1. Launch and Shutdown
- F.2. Adding
- F.3. Editing an accommodation
- F.4. Editing a contact
- F.5. Deleting a contact
- F.6. Deleting an activity
- F.7. Deleting an accommodation
- F.8. Autoschedule
- F.9. Scheduling activities
- F.10. Unschedule activity from day
- F.11. Undo an edit command
- F.12. Optimise a day
- F.13. List activity
- F.14. Set
- F.15. New
- F.16. Copyto
- F.17. Load
- F.18. View
 
1. Setting up
Refer to the guide here.
2. Design
2.1. Architecture
 
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
| The .pumlfiles used to create diagrams in this document can be found in the diagrams folder.
Refer to the Using PlantUML guide to learn how to create and edit diagrams. | 
- 
At app launch: Initializes the components in the correct sequence, and connects them up with each other. 
- 
At shut down: Shuts down the components and invokes cleanup method where necessary. 
Commons represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
- 
LogsCenter: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
- 
Defines its API in an interfacewith the same name as the Component.
- 
Exposes its functionality using a {Component Name}Managerclass.
For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.
 
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.
 
delete 1 commandThe sections below give more details of each component.
2.2. UI component
 
API : Ui.java
The UI consists of a MainWindow that is made up of parts e.g.CommandBox, FeedbackDisplay, ContactListPanel, ActivityListPanel, AccomodationListPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.
The UI component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml
The UI component,
- 
Executes user commands using the Logiccomponent.
- 
Listens for changes to Modeldata so that the UI can be updated with the modified data.
2.3. Logic component
 
API :
Logic.java
- 
Logicuses thePlannerParserclass to parse the user command.
- 
This results in a Commandobject which is executed by theLogicManager.
- 
The command execution can affect the Model(e.g. adding a contact).
- 
The result of the command execution is encapsulated as a CommandResultobject which is passed back to theUi.
- 
In addition, the CommandResultobject can also instruct theUito perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic component for the execute("add activity n/Climb Fuji a/Mount Fuji") API call.
 
add activity n/Climb Fuji a/Mount Fuji Command| The lifeline for AddCommandParsershould end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. | 
2.4. Model component
 
API : Model.java
The Model,
- 
stores a UserPrefobject that represents the user’s preferences.
- 
stores a ActivityManager,AccommodationManager,ContactManagerandItinerarythat represents the managers for activity, accommodation, contact and day respectively.
- 
exposes an unmodifiable ObservableList<Activity>,ObservableList<Accommodation>,ObservableList<Contact>andObservableList<Day>that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
- 
does not depend on any of the other three components. 
2.5. Storage component
 
API : Storage.java
The Storage component,
- 
can save UserPrefobjects in json format and read it back.
- 
application data is split into 4 different components, Accommodation,Activity,Contact,Itinerary.
2.5.1. Accommodation Storage component
 
The Accommodation Storage component,
- 
can save Accommodationobjects in json format and read it back.
- 
as Tag is a field in Accommodation, similarly JsonAdaptedTag is a field within JsonAdaptedAccommodation. Hence the association as shown in the diagram above.
- 
as Contact is a field in Accommodation, similarly JsonAdaptedContact is a field within JsonAdaptedAccommodation. Hence the association as shown in the diagram above.
2.5.2. Activity Storage component
 
API : ActivityStorage.java
- 
can save Activityobjects in json format and read it back.
- 
as Tag is a field in Activity, similarly JsonAdaptedTag is a field within JsonAdaptedActivity. Hence the association as shown in the diagram above.
- 
as Contact is a field in Activity, similarly JsonAdaptedContact is a field within JsonAdaptedActivity. Hence the association as shown in the diagram above.
2.5.3. Contact Storage component
 
API : ContactStorage.java
- 
can save Contactobjects in json format and read it back.
- 
as Tag is a field in Contact, similarly JsonAdaptedTag is a field within JsonAdaptedContact. Hence the association as shown in the diagram above.
2.5.4. Itinerary Storage component
 
API : ItineraryStorage.java
- 
can save Itineraryobjects in json format and read it back.
- 
as ActivityWithTime is a field in Day, similarly JsonAdaptedActivityWithTime is a field within JsonAdaptedDay. Hence the association as shown in the diagram above.
- 
as Activity is a field in ActivityWithTime, similarly JsonAdaptedActivity is a field within JsonAdaptedActivityWithTime. Hence the association as shown in the diagram above.
2.6. Common classes
Classes used by multiple components are in the seedu.plannerbook.commons package.
3. Implementation
This section describes some noteworthy details on how certain features are implemented.
3.1. Trip management
Plan²travel allows the user to create new trips, load and rename existing trips, make copies of existing trips and also clear existing trip information.
List of commands that helps with trip management:
- 
new n/NAME— Creates and loads a new empty trip with desired name
- 
copyto n/NAME— Creates and loads a copy of current trip using desired name
- 
load n/NAME— Loads a saved trip with desired name
- 
set n/NAME— Renames current trip to desired name
- 
clear— Clears all current trip information except for name
3.1.1. Current Implementation
A trip (or trip plan) will have a name that is identical to the directory name which it represents.
The directory will be accessible via the data/{Directory Name} directory path of the home folder
which the plan2travel.jar is stored in.
For example, a trip named "Japan Trip" will represent a Japan Trip directory. This directory can
be accessed using the data/Japan Trip directory path.
The directory will contain the accommodation.json, activity.json, contact.json and
itinerary.json of the current saved trip.
The trip management mechanism is facilitated by UserPrefs where the desired directory path is
stored internally as plannerFilePath.
Operations to access plannerFilePath are exposed in the Model interface as Model#getPlannerFilePath()
and Model#setPlannerFilePath(Path) respectively.
Given below is the sequence diagram of how the load operation works:
 
load command| The lifeline for LoadCommandshould end at the destroy marker (X) but due to a limitation of PlantUML,
the lifeline reaches the end of diagram. | 
The sequence diagram above can be described by the following sequence of events:
- 
LoadCommandis executed
- 
LoadCommandupdates theUserPrefsplannerFilePathand theItinerarynameProperty
- 
LogicManagerupdates the respective file paths (that have been updated due to changes inplannerFilePath) in theStoragecomponent
- 
LogicMangerupdates the respective lists in theModelcomponent based on the new file paths
- 
LogicManagersaves the respective lists in json format in directory designated byplannerFilePaththrough theStoragecomponent
The following activity diagram summarizes what happens when a user executes a copyto command.
 
copyto command3.1.2. Design Considerations
Aspect: How the Logic component executes set
- 
Current Choice: Deletes current directory before saving new directory containing previous json files - 
Pros: - 
Uses File#delete()which is platform-independent and helps in ensuring the stability of the application.
 
- 
- 
Cons: - 
May seem less intuitive. Deletion methods are used instead of renaming methods (which may be more appropriate given that sethelps to rename the current directory).
- 
Likely to be more costly in terms of execution as it involves deleting the previous directory and saving a new one. 
 
- 
 
- 
- 
Alternative: Rename current directory and avoid saving over the updated directory. - 
Pros: - 
Likely to be less costly in terms of execution as it does not involve deletion and saving of directories. 
 
- 
- 
Cons: - 
Uses File#renameTo()which is platform-dependent and may contribute to a less stable application.
 
- 
 
- 
Aspect: How the commands execute based on Java API methods
- 
Current Choice: Uses methods from Filesuch asFile#delete()andFile#exists()- 
Pros: - 
Methods used do not throw an IOExceptionand may help ensure the stability of the application.
 
- 
- 
Cons: - 
It may be difficult to diagnose issues that may arise. 
 
- 
 
- 
- 
Alternative: Uses methods from Filessuch asFiles#deleteIfExists()andFiles#list(Path)- 
Pros: - 
Methods can throw an IOExceptionwhich can help to diagnose issues.
 
- 
- 
Cons: - 
However, certain usages of these methods can result in an AccessDeniedExceptionwhich contributes to a less stable application.
 
- 
 
- 
3.2. Undo/Redo feature
The undo command allows user to undo by one command (if the command is undoable).
The redo command allows user to return to the original state before latest undo.
3.2.1. Implementation
The undo/redo feature utilizes various classes to operate, such as CommandHistory class and the
classes within the events package in the logic component.
CommandHistory is a static class that contains the undoEventStack and redoEventStack of the application, each containing Events.
KEY IDEA:
| Event — Every UndoableCommand can be wrapped into its own unique Event. | 
List of UndoableCommand:
| add activity/ accommodation/ contact/ days | 
| delete activity/ accommodation/ contact/ day | 
| edit activity/ accommodation/ contact | 
| schedule | 
| unschedule | 
| autoschedule | 
| optimise | 
| clear | 
Step 1. The user executes an UndoableCommand.
Step 2. The UndoableCommand is executed, generating an Event in the process.
Step 3. EventFactory will parse the UndoableCommand to generate an Event.
(eg. DeleteActivityCommand will result in DeleteActivityEvent generated)
| EventFactory is a static class that will parse an UndoableCommand and generate the corresponding Event. | 
Step 4. Event is added to undoEventStack stored in CommandHistory. The redoEventStack in
CommandHistory is also cleared upon generating a new Event.
Step 5. The UndoableCommand has been executed, returning a CommandResult to be shown.
Step 6. To undo the previous UndoableCommand, the user executes undo command. An UndoCommand is generated.
Step 7. UndoCommand is not an UndoableCommand. Executing the UndoCommand gets the Event from the top of undoEventStack
and calls the undo method of Event.
| Both UndoCommand and RedoCommand are not UndoableCommands, no Events are generated. | 
Step 8. The Event is popped from the undoEventStack and pushed to redoEventStack in CommandHistory. A CommandResult
is returned and the Event is undone.
Step 9. To redo the command that has been undone, the user executes redo command. A RedoCommand is generated and it
is not an UndoableCommand. This execution is similar to steps 6 and 7, except Event is popped from redo stack instead and pushed to undo stack.
The following two sequence diagrams shows how the user’s input is handled for 'delete activity 1'.
The first diagram below shows the execution of 'delete activity 1' command. It shows how the Event is generated and how the
undoEventStack and redoEventStack is updated.
 
| When DeleteActivityCommand is executed, it generates the activityToDeleteby extracting theActivityto be deleted from
the Model’s list of activities based on the index specified in user’s command input. It then calls the Model’sdeleteActivitymethod. | 
The second diagram below shows the execution of undo command. Executing UndoCommand calls undo of the DeleteActivityEvent,
which returns an AddActivityCommand with the Activity (initially deleted) to be added back at the correct index.
Both Activity and Index were stored in DeleteActivityEvent.
This new AddActivityCommand is executed, and the DeleteActivityCommand is successfully undone.
 
| Each Event stores the necessary datarequired by the reverse Command to undo the effects of the initial
UndoableCommand.(eg. AddActivityEvent stores the Activity added, asDeleteActivityCommandrequires the Activity to undo
the initialAddActivityCommand’schanges) | 
The following activity diagram summarizes what happens when a user executes an UndoableCommand, an UndoCommand, a RedoCommand, or any other Commands.
 
| If the user does not execute an UndoableCommand, UndoCommand or RedoCommand, the stack of Events in CommandHistory will not be affected. (eg. view, list commands) | 
3.2.2. Design Considerations
Aspect: How undo & redo executes
- 
Option 1 : Wrap every UndoableCommand in an Event class, which has undo and redo methods. - 
Pros: - 
Uses less memory by storing Event objects rather than storing every state of the Model. 
- 
Convenient for future extensions for new Commands added. Just need to ensure for every UndoableCommand, there must be a Command that is able to undo its changes. 
- 
Command classes obey Single Responsibility Principle, they do not need to know how to undo or redo itself, as it is abstracted to their corresponding Event classes. 
 
- 
- 
Cons: - 
Every UndoableCommand requires another Command to undo its changes. Might be difficult to manage if more UndoableCommands are added. 
 
- 
 
- 
- 
Option 2 : Saves the entire Model data (comprising of accommodations, activities, contacts and days). - 
Pros: - 
Easy to implement. 
 
- 
- 
Cons: - 
May have performance issues in terms of memory usage. Expensive to store the various objects at every state. 
 
- 
 
- 
Aspect: Data structure to support the undo/redo commands
- 
Option 1 (current choice): Use of static class CommandHistory to store a stack of Events to undo, and a stack of Events to redo. - 
Pros: - 
Easy to implement and understand. Every Event object is generated through EventFactory and stored in CommandHistory. 
 
- 
- 
Cons: - 
Static class is used instead of Singleton implementation. No single instance of CommandHistory is created, cannot be passed as a parameter to other methods and treated as a normal object, hence might pose a difficulty during extensions. 
 
- 
 
- 
- 
Option 2: Create a HistoryManager class to store a single list of Model objects for undo/redo - 
Pros: - 
Straightforward and easy implementation, storing a deep copy of Model whenever an UndoableCommand is executed. 
 
- 
- 
Cons: - 
Need to keep track of the Model object obtained from the list to set during Undo/Redo. Difficult to manage the pointer in the list. 
 
- 
 
- 
3.3. Schedule optimisation
3.3.1. Implementation
Scheduled activities in a day can be modeled as a Directed Acyclic Graph (DAG) where the vertices are the activities and an edge from 1 vertex to another means that the activities are not overlapping. Just like DAGs, there are no cycles within the schedule due to the linearity of time.
When the command is executed, an adjacency list is formed from the existing activities within the schedule. The paths are then traced, with the help of a utility method, from the adjacency list to find all possible combinations of activities such that there are no overlaps between activities. The list of paths are then sorted
by their total cost. If there are multiple paths with the same total cost, the one with the most number of activities is selected. The existing day is then replaced with a day that contains the new schedule made from the path.
- 
optimise INDEX_OF_DAY — optimises and de-conflicts the schedule. This operation supports activities with or without a cost. Activities without a cost have a default cost of $0.00. 
Given below is a sample usage of the feature:
The user calls optimise command on an existing day with overlapping activities within its schedule. This results in a schedule without overlaps such that the lowest overall cost and the most number of activities if there are multiple combinations with the same total cost, such that the user’s time is maximised.
Shown below is a summary of the execution of the command.
 
3.3.2. Design considerations
Aspect: Algorithm to de-conflict
- 
Alternative 1 (current): Find all combinations, if the total cost is the same, combination with more activities is selected. - 
Pros: - 
Allow users to maximise time by squeezing more activities into the schedule. 
- 
Allow optimisation to cover more criteria such as cost, number of activities, etc. 
 
- 
- 
Cons: - 
Costly runtime. 
 
- 
 
- 
- 
Alternative 2: Use Single Shortest Path (SSSP) algorithms to find a combination without conflicts. - 
Pros: - 
Fast runtime. 
 
- 
- 
Cons: - 
Use of SSSP algorithms like Djikstra or Bellman Ford restricts the criteria of optimisation due to the limits of edge weight (i.e. cost). 
 
- 
 
- 
Aspect: De-conflict process
- 
Alternative 1 (current): Model as a DAG and find combination with the lowest overall cost. - 
Pros: - 
Easy for users to use, less hassle for indecisive users. 
 
- 
- 
Cons: - 
Less control for the user to choose activity. 
 
- 
 
- 
- 
Alternative 2: Allow users to manually de-conflict by selecting individual activities they wish to keep. - 
Pros: - 
Users have more control over activities. 
 
- 
- 
Cons: - 
Users have to enter multiple inputs to de-conflict. 
 
- 
 
- 
3.4. Schedule feature
Plan²travel allows user to schedule an activity from the activity list to a specified time of a day.
This is accomplished by executing the ScheduleCommand with activity index, start time and  day index.
Eg. schedule ACTIVITY_INDEX st/START_TIME d/DAY_INDEX
3.4.1. Current Implementation
The keywords from the command given by user is parsed using ScheduleCommandParser which converts the string variable of start time into a LocalDateTime object, while activity index and day index are converted into Index objects.
These are then passed to the ScheduleCommand for execution later on.
Given below is a sequence diagram showing the creation of ScheduleCommand:
 
After the creation of ScheduleCommand, LogicManager will proceed to call the execute() method of ScheduleCommand.
Below are the steps taken during the execution of ScheduleCommand:
- 
Modelwill retrieve the list of days from theItineraryand the list of activities fromUniqueActivityList.
- 
The activityIndexanddayIndexwill then be used to obtain the targetedActivityfrom activity list and targetedDayfrom list of days.
- 
Activitywill be converted toActivityWithTimeusing thestartDateTimeanddurationof activity.
- 
This ActivityWithTimeis then added to the list ofActivityWithTimein the targetDay.
- 
The list of ActivityWithTimeis sorted according ActivityWithTime startDateTime.
Given below is a sequence diagram showing the execution of ScheduleCommand:
 
3.4.2. Design Consideration
Aspect: Update activities for that particular day
- 
Current Choice: Directly updates the activity list in the targeted Dayclass.- 
Pros: Seem more intuitive and simple to implement. 
- 
Cons: Might make it harder to debug error that surface if many other functions/classes also depends on the same Dayclass.
 
- 
- 
Alternative: Create a new Dayclass with the new updated activity list to replace the targetedDayclass.- 
Pros: Easier for developer to test the code. 
- 
Cons: Might create unnecessary overheads in the code by creating new object every time we schedule an activity. 
 
- 
3.5. Auto Schedule feature
3.5.1. Rationale
There are times when users are planning for an overseas trip, there are so many activities in their activity list that they want to do but the problems faced are that they are unable to finish all the activities in the list or they are unable to find an optimal schedule plan.
3.5.2. Overview
The autoschedule command requires user to specify either the tag name or the activity name itself in order of the type of activity that they want.
For example, t/shopping t/sightseeing t/dining would means an activity of shopping type would be scheduled first followed by sightseeing and then dining.
Before using the autoschedule command, users are to fill up their activity list first and ensure that they have input the duration for each activity and are recommended to input their priority for those activities.
Afterwards, autoschedule would serve to ensure that the activities scheduled do not overlap, are according to what the users prioritised first and that all activities have a chance to be scheduled.
3.6. Implementation
The keywords from the command given by the user is parsed using AutoScheduleCommandParser which converts all the tag or name prefix’s argument with their respective start time ,if given, in NameOrTagWithTime class and stores them in a list to maintain the same ordering as given by the user.
If address is specified, it is wrapped in an Address class and if the day index(es) to schedule are specified, they stored in a list with each index wrapped in an Index class.
The list of NameOrTagWithTime, address and list of day indexes are then passed to the AutoScheduleCommand for execution later on.
Given below is a sequence diagram showing the creation of AutoScheduleCommand:
 
AutoScheduleCommand is created.Below are the steps taken when executing of the AutoScheduleCommand:
Step 1. AutoScheduleCommand will firstly get the list of days and list of activities from the Model class
Step 2. If address is specified, the list of activities will be filtered to get all activities that has the same address.
Step 3. If no day indexes to schedule are being specified, AutoScheduleCommand will generate a schedule for all days.
Below shows the checks taken by AutoScheduleCommand:
 
AutoScheduleCommand checks the requirement given by user:After filtering the activity list, AutoScheduleCommand will proceed to begin preparation for the scheduling of the first activity of those specified day(s).
Step 4. It will filter the activity list that has been filtered by address to get all the activities with the same tag or activity name as the first activity to schedule.
Step 5. After which it will sort the list such that the activity that has not been scheduled will be scheduled first.It will ensure that for cases where both activities has not been scheduled before, the one with the higher priority will be scheduled first.
 
AutoScheduleCommand handles the preparation for the scheduling of the first activity:Step 6. Next, AutoScheduleCommand will check if the chosen activity to be scheduled does not overlap with the start time of the next activity if user specify.
Step 7. If the chosen activity overlaps, it will traverse the filtered list, picking the next activity with the next lowest count in the itinerary and check if it overlaps. The process will continue until it finds a suitable activity or it has finished traversing the whole filtered list. If it is planning for the last activity of the day, it will instead check whether the activity chosen overlap til the next day.
 
AutoScheduleCommand finds an activity to schedule:Step 4 to Step 7 will repeat for the next activity to schedule for that day until it finished scheduling for that day or it could not find a suitable activity to schedule. If there other days to schedule, the steps taken will also be the same as Step 4 to Step 7.
3.6.1. Design Considerations
Aspect: Counting the number of times similar activity of the same name or tag appears in the list
- 
Current Choice: Count the number of times all the similar activities appear in the itinerary every time we are planning to schedule an activity. - 
Pros: It will ensure that the count number for the similar activities will always be right before they are chosen to be scheduled 
- 
Cons: Slow down the program as we have to traverse through all the activities for each day everytime we are planning to schedule for an activity. 
 
- 
- 
Alternative: Have a counter inside the activity itself to keep track - 
Pros: Significantly improve the runtime speed and less complicated to implement 
- 
Cons: Over time, the count might be inaccurate due to multiple scheduling and unscheduling which alter the count number and we might not have keep track of it at certain point of time. 
 
- 
Aspect: Account for travelling time
- 
Current Choice: Allows user to input the start time of activity - 
Pros: Gives user the flexibility and they are better able to gauge the travelling time of each activity 
- 
Cons: It restrict the number of possible activities that could be scheduled as we have to consider activity not overlapping with the start time of the next activty. 
 
- 
- 
Alternative: Fix a break of 30min between every activity to acount for travel time - 
Pros: Activities that user prioritised are more likely to be scheduled as we do not have to consider overlap of the start time of next activity. 
- 
Cons: Certain activity may require more travelling time. If we fix a longer travelling time, it might not be optimising the schedule plan as certain activity might have shorter travelling time. 
 
- 
3.7. Auto Complete feature
3.7.1. Rationale
There are many commands to learn in our program and some of the commands can be wordy. In order to ease the learning curve and to help the user be productive as quickly as possible, autocomplete was implemented.
3.7.2. Implementation
KEY IDEA:
Every command in the planner can be broadly broken down into a few categories, namely:
- 
Command Word 
- 
Preamble 
- 
Required Prefix - 
That are used once 
- 
That are used multiple times 
 
- 
- 
Optional Prefix - 
That are used once 
- 
That are used multiple times 
 
- 
AutoCompleteSuggester makes use of this and checks the input for these categories one by one.
- 
If the input lacks the command word, then the best matching command word will be suggested. 
- 
If the command word is provided, but the preamble is not (and it is required by the command), then the preamble will be suggested. 
- 
If the input contains the command word and contains the preamble(when necessary), then the required prefixes and optional prefixes will be suggested. Since there are some prefix that should only be used, the input will be checked to see if these prefixes are present and remove them from the suggestions. 
The AutoCompleteParser supports the AutoCompleteSuggester by parsing the user input into the command word, the preamble and a list of prefixes used in the program.
Given below is a sequence diagram showing the generation of suggestions:
 
 
Below is how the autocomplete feature is triggered:
Step 1. Modification in the text of AutoCompleteTextField is detected.
Step 2. If the input is empty, hide the pop-up box which contains the suggestions. If not empty, get entries (suggestions) for the pop-up box.
Step 3. If there are entries, populate the pop-up box with it. Else, hide the pop-up box.
Step 4. If pop-up box in previous step was populated, then show the pop-up box to the user.
 
Below is how entries for the pop-up box is obtained:
Step 1. Check if input contains '<' or '>', as that would indicate that the user has accepted the suggestion of preamble, which has description enclosed with < and > (for e.g. <INDEX>) but has not replaced it with the actual preamble. If it has '<' or '>', then don’t give suggestions to user.
Step 2. If the input does not contain '<' or '>', parse the command word.
Step 3. Next check if command word can be found. If it is not found, suggest command words that partially matches what the user has already inputted. If command word was found, do a check if there is a space at the end of the input.
Step 3. Next check if command word can be found. If it is not found, suggest command words that partially matches what the user has already inputted. If command word was found, do a check if there is a space at the end of the input.
Step 4. If there is no space, don’t give suggestions to the user as it is assumed that the user is still typing. If there is a space, then parse preamble, parse prefix and make suggestions based on the command word, preamble and prefix present in the input.
 
3.7.3. Design Considerations
Aspect: Underlying data structure to store the command words
- 
Current Choice: Use an ArrayList - 
Pros: Simple to implement. 
- 
Cons: Might be slow in providing suggestion for the command word, as in the worse case, it needs to iterate through every command word entry and check with every entry. 
 
- 
- 
Alternative: Use a Trie - 
Pros: Faster in providing suggestion for command word as it only has to iterate through the length of the input. 
- 
Cons: More complicated to implement. The Trie also needs to be built during startup. 
 
- 
- 
Reason for choice: Given that the program does not have many commands and unlikely to have a significant number more commands in the future, search times are not an issue. 
Aspect: Checking if the user has completed typing the command word/preamble/prefix content
- 
Current Choice: Assumes the user has finished the command word/preamble/prefix content when there is a whitespace at the end of input - 
Pros: Simple to implement. Works in most cases. 
- 
Cons: Might be wrong when suggesting new prefix as there are some commands like autoschedule that have prefixes that can have 2 arguments (autoschedule t/argument1 argument2 d/argument1 argument2…) 
 
- 
- 
Alternative: Waits for a specific duration of time before giving user suggestions - 
Pros: More likely to provide suggestions when the user needs it. 
- 
Cons: There might be a noticeable delay in the suggestions appearing if the specific duration is too long. More complicated to implement. 
 
- 
3.8. Timetable
3.8.1. Current Implementation
Internally, Timetable is a List of ActivityWithTime. This gives the Timetable flexibility to accept Activities that start and end at any time instead of fixed intervals (e.g. 30 minute intervals) while allow for conflicting ActivityWithTime.
3.8.2. Design considerations
- 
Alternative 1: an Array of time slots that stores Activity - 
Pros: Simple and intuitive to implement. UI for itinerary is easier to implement too. Very fast access to each Activity in the Timetable. 
- 
Cons: Constrained to fixed intervals. Hence, Activity start times and end times have to be in multiples of the fixed interval. 
 
- 
- 
Alternative 2: a TreeSet of ActivityWithTime - 
Pros: Allows flexible start times and end times. Fast access to Activity in Timetable. Does not allow ActivityWithTime objects to have the same start times. 
- 
Con: UI for itinerary might be difficult to implement as each the size of each block of ActivityWithTime in the UI is not the same. Does not allow for conflicting startDateTime between ActivityWithTime. 
 
- 
- 
Alternative 3(current choice): a List of ActivityWithTime - 
Pros: Allows flexible start times and end times. ActivityWithTime can have the same startDateTime, thus allowing conflicting ActivityWithTime. 
- 
Con: UI for itinerary might be difficult to implement as each the size of each block of ActivityWithTime in the UI is not the same. Slower access time if the size of the List is large. 
 
- 
3.9. Logging
We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.
- 
The logging level can be controlled using the logLevelsetting in the configuration file (See Section 3.10, “Configuration”)
- 
The Loggerfor a class can be obtained usingLogsCenter.getLogger(Class)which will log messages according to the specified logging level
- 
Currently log messages are output through: Consoleand to a.logfile.
Logging Levels
- 
SEVERE: Critical problem detected which may possibly cause the termination of the application
- 
WARNING: Can continue, but with caution
- 
INFO: Information showing the noteworthy actions by the App
- 
FINE: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
3.10. Configuration
Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).
4. Documentation
Refer to the guide here.
5. Testing
Refer to the guide here.
6. Dev Ops
Refer to the guide here.
Appendix A: Product Scope
Target user profile:
- 
a student who is inexperienced in planning for overseas trips 
- 
has a need to manage and schedule planner items 
- 
prefer desktop apps over other types 
- 
can type fast 
- 
prefers typing over mouse input 
- 
is reasonably comfortable using CLI apps 
Value proposition: Many students wish to go for overseas trips during their holidays. They may be inexperienced in trip planning. These students would benefit from having a template as a way to organise the information they have for their trip. Plan²travel can organise information faster than a typical mouse/GUI driven app.
Appendix B: User Stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… | 
|---|---|---|---|
| 
 | traveller | refer to a list of attractions | I can decide on what activities to do for the day | 
| 
 | traveller | add activities that I want to do | I can plan my trip | 
| 
 | traveller | save my contact list | I can review/access them again | 
| 
 | traveller | access a list of accommodations | I can better plan for where to stay at | 
| 
 | organised traveller | plan my daily planner | I can make better use of my travel time | 
| 
 | lightweight traveller | save the planner to my phone | I can pack light | 
| 
 | infrequent traveller | add contacts | I can get in touch with the hotel concierge | 
| 
 | new user | view a help guide | I can familiarise myself with the application | 
| 
 | traveller | categorise activities by interest | I can prioritise certain activities | 
| 
 | solo traveller | keep a list of emergency contacts | I know who to contact in times of emergency | 
| 
 | eager traveller | follow an accommodation checklist | I will not miss out on anything | 
| 
 | indecisive traveller | plan for multiple trips | I can decide on a later date | 
| 
 | messy planner | quickly organise my travel research | I can streamline my planning processes | 
| 
 | fast typist | be auto-corrected for my typos | I won’t break my train of thought while planning | 
| 
 | advanced user | use command shortcuts | I can improve my planning efficiency | 
| 
 | advanced user | set where to save my itineraries | I can organise my itineraries | 
| 
 | careless user | undo my mistakes | I don’t have to retype if I make one | 
| 
 | traveller | rate activities that I have done | I can make a better recommendation to my friends | 
| 
 | traveller on a tight budget | estimate my budget for a trip | I can minimise my spendings | 
| 
 | traveller | organise and record my travel experiences | I can share them online | 
| 
 | inexperienced planner | receive planning recommendations | I can improve my planner | 
Appendix C: Use Cases
(For all use cases below, the System is the Plan²travel application and the Actor is the user, unless specified otherwise)
Use case: Schedule activity
MSS
- 
User requests to schedule activity 
- 
System shows a list of days and activities 
- 
User requests to add a specific accommodation to a specific day 
- 
System adds accommodation under selected day Use case ends. 
Extensions
- 
2a. The list of days is empty. - 
Use case ends. 
 
- 
- 
2b. The list of activities is empty. - 
Use case ends. 
 
- 
- 
3a. The day number is invalid. - 
3a1. System shows an error message. Use case resumes at step 2. 
 
- 
- 
3b. The accommodation index is invalid. - 
3b1. System shows an error message. Use case resumes at step 2. 
 
- 
Use case: Add Contact
MSS
- 
User requests to add a new Contact 
- 
System adds the new Contact into the database Use case ends. 
Extensions
- 
1a. The new Contact’s syntax is not entered correctly. - 
1a1. System shows a feedback to the user that the Contact was not entered correctly. 
- 
Use case ends. 
 
- 
Use case: Undo command
MSS
- 
User requests to undo last possible command 
- 
System reverts to state before the last possible command Use case ends. 
Extensions
- 
1a. There is no last possible command. - 
Use case ends. 
 
- 
{More to be added}
Appendix D: Non Functional Requirements
Availability
- 
Application should work on any mainstream OS as long as it has Java 11or above installed.
Performance
- 
Application should respond within 2 seconds of client’s query. 
Usability
- 
Application should be easy to use for new user when following the User Guide. 
- 
Application’s interface should be intuitive and easy to understand for the user. 
- 
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. 
Reliability
- 
Application should be able to execute all user’s commands without failing. 
Appendix F: Instructions for Manual Testing
Given below are instructions to test the app manually.
| These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. | 
F.1. Launch and Shutdown
- 
Initial launch - 
Download the jar file and copy into an empty folder 
- 
Double-click the jar file 
 Expected: Shows the GUI with a set of sample activities, accommodations, contacts and days filled with activities. The window size may not be optimum.
 
- 
F.2. Adding
F.2.1. Adding activities
- 
Add a new activity to the planner - 
Prerequisites: Arguments are valid and compulsory parameters are provided. 
- 
Test case: add activity n/Swim at the beach a/Glass Beach du/180 p/12345678 pr/1 t/Fun
 Expected: Adds an activity named "Swim at the beach", with address "Glass Beach", a duration of 180 minutes, a contact with the phone number 12345678, a priority level of 1 and with the tag "Fun".
- 
Test case: add activity n/Swim at the beach
 Expected: No activity is added. Error details shown in the feedback display.
- 
Other incorrect add commands to try: add activity a/Glass Beach,add activity n/Swimming du/120
 Expected: Similar to previous
 
- 
F.2.2. Adding accommodations
- 
Add a new activity to the planner - 
Prerequisites: Arguments are valid and compulsory parameters are provided. 
- 
Test case: add accommodation n/Hotel 87 a/Hilton Crescent p/12345678 t/Cozy
 Expected: Adds an accommodation named "Hotel 87", with address "Hilton Crescent", a contact with phone number 12345678, and with the tag "Cozy".
- 
Test case: add accommodation n/Hotel 123
 Expected: No accommodation is added. Error details shown in the feedback display.
- 
Other incorrect add commands to try: add accommodation a/Kappa street,add accommodation p/87654321 t/lmao
 Expected: Similar to previous
 
- 
F.2.3. Adding contacts
- 
Add a new contact to the planner - 
Prerequisites: Arguments are valid and compulsory parameters are provided. 
- 
Test case: add contact n/Allan p/12345678 e/example@example.com t/Budz
 Expected: Adds a contact named "Allan", with phone number 12345678, an email of "example@example.com" and with the tag "Budz".
- 
Test case: add contact n/Big Brother
 Expected: No contact is added. Error details shown in the feedback display.
- 
Other incorrect add commands to try: add contact a/Kappa street,add contact p/87654321 t/lmao
 Expected: Similar to previous
 
- 
F.2.4. Adding days
- 
Add days to the itinerary - 
Prerequisites: Arguments are valid, and NUMBER_OF_DAYS being added and number of days currently in itinerary do not exceed 15. 
- 
Test case: add days 2
 Expected: Adds two days to the itinerary. Else, invalid message will be shown.
- 
Test case: add days 16
 Expected: No days is added. Error details shown in the feedback display.
- 
Other incorrect add commands to try: add days abc,add days -1
 Expected: Similar to previous === Editing an activity- 
Editing an activity’s name 
 
- 
- 
Test case: Edit activity 1 n/Visit Mount FujiExpected: The first activity in the activity list has its name being edited toVisit Mount Fuji.- 
Editing an activity’s address 
 
- 
- 
Test case: Edit activity 1 a/TokyoExpected: The first activity in the activity list has its address being edited toTokyo.
 
- 
F.3. Editing an accommodation
- 
Editing an accommodation’s name - 
Test case: Edit accommodation 1 n/Shinjuku hotelExpected: The first activity in the activity list has its name being edited toShinjuku hotel.
 
- 
- 
Editing an accommodation’s address - 
Test case: Edit accommodation 1 a/TokyoExpected: The first accommodation in the accommodation list has its address being edited toTokyo.
 
- 
F.4. Editing a contact
- 
Editing a contact’s name - 
Test case: Edit contact 1 n/Uncle BobExpected: The first contact in the contact list has its name being edited toUncle Bob.
 
- 
- 
Editing a contact’s phone number - 
Test case: Edit contact 1 a/90001112Expected: The first contact in the contact list has its phone number being edited to90001112.
 
- 
F.5. Deleting a contact
- 
Removes a contact from contact list - 
Test case: delete contact 2Expected: Deletes the 2nd contact in the contact list.
 
- 
F.6. Deleting an activity
- 
Removes an activity from contact list - 
Test case: delete activity 2Expected: Deletes the 2nd activity in the activity list.
 
- 
F.7. Deleting an accommodation
- 
Removes an accommodation from accommodation list - 
Test case: delete accommodation 2Expected: Deletes the 2nd accommodation in the accommodation list.
 
- 
F.8. Autoschedule
- 
Generate a schedule for specified day(s) based on the tags or activity name given. - 
Prerequisites: Ensure the tag or activity name is present in activity list. 
- 
Test case: autoschedule t/sightseeing 1030 t/dining 1200 d/1Expected: An activity of sightseeing tagged has been scheduled at 1030 followed by another activity of dining tagged scheduled at 1200 on day 1.
 
- 
F.9. Scheduling activities
F.9.1. Schedule
- 
Schedule an activity to a day at a certain time - 
Prerequisites: Arguments are valid, and end date time of the activity must not be after the end of the trip. Also, the provided index for both activity and day must be less than or equal to the size of their respective list(activity list, itinerary). 
- 
Test case: schedule 1 d/1 st/1000
 Expected: Schedules activity 1 into day 1 at time 10am.
- 
Test case: schedule 1 d/16 st/1000
 Expected: Nothing is scheduled. Invalid message shown.
- 
Other incorrect add commands to try: schedule d/1 st/1111,schedule 1 d/1
 Expected: Similar to previous === Undo a delete command- 
Retrieve the information that has been deleted. 
 
- 
- 
Prerequisites: Delete activity 1has been executed.
- 
Test case: undo
- 
Expected: The activity initially in the first index of the activity list has been added back to the activity list. 
 
- 
F.10. Unschedule activity from day
- 
Unschedules an activity from a day - 
Prerequisites: Arguments are valid. Also, the index for the preamble is the index of the activity within the day(as shown from list day). Day DAY_INDEX must exist in the itinerary. 
- 
Test case: unschedule 1 d/1
 Expected: Unschedules the first activity in day 1.
- 
Test case: unschedule d/16 st/1000
 Expected: Nothing is unscheduled. Invalid message shown.
- 
Other incorrect add commands to try: unschedule 1,unschedule 1 d/16
 Expected: Similar to previous === Undo an add command- 
Delete the information that has been added. 
 
- 
- 
Prerequisites: add activity n/Visit Mount Fuji a/Tokyo du/30has been executed.
- 
Test case: undo
- 
Expected: The activity Visit Mount Fujiis deleted from the activity list.
 
- 
F.11. Undo an edit command
- 
Return back to the original state before it has been edited. - 
Prerequisites: edit contact n/Bobhas been executed.
- 
Test case: undo
- 
Expected: The contact name of Bobis deleted and is replaced by the original name before it has been edited.
 
- 
F.12. Optimise a day
- 
Remove all overlapping for the day and generate a schedule with the lowest budget for the day being optimised. - 
Prerequisites: There are activities scheduled for the specified day to optimise. 
- 
Test case: optimise 1
- 
Expected: Activities that are non-overlapping and they have the lowest cost in total are chosen for that day. 
 
- 
F.13. List activity
- 
All activities in activity list are listed - 
Test case: list activity
- 
Expected: All activities are listed in the information panel. 
 
- 
F.14. Set
- 
Sets the name or start date of the itinerary - 
Prerequisites: Arguments are valid. A minimum of either name or start date must be provided. 
- 
Test case: set n/Germany sd/25-12-2019
 Expected: Sets the itinerary name to Germany and start date to 25th Dec 2019.
- 
Test case: set
 Expected: Nothing is set. Invalid message shown.
- 
Other incorrect add commands to try: set sd/12/12/2019
 Expected: Similar to previous
 
- 
F.15. New
- 
Creates and loads a new empty trip with desired name - 
Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided. 
- 
Test case: new n/Japan Trip
 Expected: Creates a new empty trip named "Japan Trip". The name is reflected as the itinerary name.
- 
Test case: new
 Expected: Planner name not specified
- 
Test case: new n/Iceland Trip,new n/Iceland Trip
 Expected: This planner already exists
 
- 
F.16. Copyto
- 
Creates and loads a copy of current trip using desired name - 
Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided. 
- 
Prerequisites: Populate a new trip using the following commands: - 
new n/China v1
- 
add activity n/Visit QinShiHuang’s Tomb a/Xi An du/240 t/history
- 
add accommodation n/China World Hotel a/Beijing t/5star
 
- 
- 
Test case: copyto n/China v2
 Expected: Creates a copy of the current trip named "China v2". The name is reflected as the itinerary name and is the only visible difference when compared to the original trip.
- 
Test case: copyto
 Expected: Planner name not specified
- 
Test case: copyto n/China v1
 Expected: This planner already exists
 
- 
F.17. Load
- 
Loads a saved trip with desired name - 
Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided. 
- 
Prerequisites: Populate 2 new trips using the following commands: - 
new n/China
- 
add activity n/Visit QinShiHuang’s Tomb a/Xi An du/240 t/history
- 
add accommodation n/China World Hotel a/Beijing t/5star
- 
new n/Japan
- 
add accommodation n/Crowne Hotel a/Tokyo p/8137973142 t/5stars
- 
add activity n/Visit Aquarium a/Tokyo p/812487941 du/120 c/20.00 pr/3 t/marine
 
- 
- 
Test case: load n/China
 Expected: Loads the existing trip that has the name "China". The name is reflected as the itinerary name.
- 
Test case: load
 Expected: Planner name not specified
- 
Test case: load n/China
 Expected: This planner has already been loaded
 
- 
F.18. View
F.18.1. View activity/accommodation/contact
- 
Views information about an activity/accommodation/contact - 
Prerequisites: Argument is valid. The provided index for activity must be less than or equal to the size of the activity list. 
- 
Test case: view activity 1/view accommodation 1/view contact 1
 Expected: Views the information about activity/accommodation/contact 1.
- 
Test case: view activity abc/view accommodation abc/view contact abc
 Expected: No information about activity/accommodation/contact appear. Invalid message shown.
 
- 
F.18.2. View itinerary/info/help
- 
Switch tab to itinerary/info/help - 
Test case: view itinerary/view info/view help
 Expected: Switches tab to itinerary/info/help.
 
- 
F.18.3. Redo
- 
Redo the last undo command. - 
Prerequisites: Only to be used if undo had been used. 
- 
Test case: redo
 Expected: Redo the last undo command.
 
-