Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2021S1#74 from nicholasyeo/branch-tim…
Browse files Browse the repository at this point in the history
…etable-storage

Allow fitNUS to save and load timetable slots
  • Loading branch information
khor-jingqian authored Oct 20, 2020
2 parents 643120f + 573a381 commit 5275d7d
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/main/java/seedu/address/logic/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import seedu.address.model.person.Lesson;
import seedu.address.model.person.Person;
import seedu.address.model.person.Routine;
import seedu.address.model.person.Slot;

/**
* API of the Logic component
Expand Down Expand Up @@ -45,6 +46,9 @@ public interface Logic {
/** Returns an unmodifiable view of the filtered list of lessons */
ObservableList<Lesson> getFilteredLessonList();

/** Returns an unmodifiable view of the filtered list of slots */
ObservableList<Slot> getFilteredSlotList();

/**
* Returns the user prefs' address book file path.
*/
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import seedu.address.model.person.Lesson;
import seedu.address.model.person.Person;
import seedu.address.model.person.Routine;
import seedu.address.model.person.Slot;
import seedu.address.storage.Storage;

/**
Expand Down Expand Up @@ -77,10 +78,16 @@ public ObservableList<Routine> getFilteredRoutineList() {
return model.getFilteredRoutineList();
}

@Override
public ObservableList<Lesson> getFilteredLessonList() {
return model.getFilteredLessonList();
}

@Override
public ObservableList<Slot> getFilteredSlotList() {
return model.getFilteredSlotList();
}

@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/seedu/address/model/AddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ public void setLessons(List<Lesson> lessons) {
this.lessons.setLessons(lessons);
}

/**
* Replaces the contents of slot list with {@code slots}.
* {@code slots} must not contain duplicate slots or overlapping slots.
*/
public void setSlots(List<Slot> slots) {
timetable.setSlots(slots);
}

/**
* Resets the existing data of this {@code AddressBook} with {@code newData}.
*/
Expand All @@ -114,6 +122,7 @@ public void resetData(ReadOnlyAddressBook newData) {
setExercises(newData.getExerciseList());
setLessons(newData.getLessonList());
setRoutines(newData.getRoutineList());
setSlots(newData.getSlotList());
}

//// person-level operations
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/seedu/address/model/person/Duration.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

public class Duration {
Expand Down Expand Up @@ -89,6 +90,7 @@ public int hashCode() {

@Override
public String toString() {
return startTime.toString() + " to " + endTime.toString();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HHmm");
return startTime.format(formatter) + "-" + endTime.format(formatter);
}
}
2 changes: 1 addition & 1 deletion src/main/java/seedu/address/model/person/Slot.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ public int hashCode() {

@Override
public String toString() {
return activity.getName() + " on " + day.toString() + " from " + duration.toString();
return activity.getName() + " on " + day.toString() + " " + duration.toString();
}
}
6 changes: 6 additions & 0 deletions src/main/java/seedu/address/model/person/Timetable.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static java.util.Objects.requireNonNull;

import java.util.List;

import javafx.collections.ObservableList;

public class Timetable {
Expand Down Expand Up @@ -40,6 +42,10 @@ public void deleteSlot(Slot slot) {
slots.remove(slot);
}

public void setSlots(List<Slot> slots) {
this.slots.setSlots(slots);
}

public ObservableList<Slot> getSlotList() {
return slots.asUnmodifiableObservableList();
}
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/seedu/address/model/person/UniqueSlotList.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static java.util.Objects.requireNonNull;

import java.util.Iterator;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
Expand Down Expand Up @@ -72,6 +73,56 @@ public void remove(Slot toRemove) {
}
}

public void setSlots(UniqueSlotList replacement) {
requireNonNull(replacement);
internalList.setAll(replacement.internalList);
}

/**
* Replaces the contents of this list with {@code slots}.
* {@code slots} must not contain duplicate slots.
*/
public void setSlots(List<Slot> slots) {
requireNonNull(slots);
if (!areSlotsUnique(slots)) {
throw new DuplicateSlotException();
}

if (areSlotsOverlapping(slots)) {
throw new SlotOverlapDurationException();
}

internalList.setAll(slots);
}

/**
* Returns true if {@code slots} contains only unique slots.
*/
public boolean areSlotsUnique(List<Slot> slots) {
for (int i = 0; i < slots.size() - 1; i++) {
for (int j = i + 1; j < slots.size(); j++) {
if (slots.get(i).isSameSlot(slots.get(j))) {
return false;
}
}
}
return true;
}

/**
* Returns true if {@code slots} contains no overlapping slots.
*/
public boolean areSlotsOverlapping(List<Slot> slots) {
for (int i = 0; i < slots.size() - 1; i++) {
for (int j = i + 1; j < slots.size(); j++) {
if (slots.get(i).hasOverlapDuration(slots.get(j))) {
return true;
}
}
}
return false;
}

/**
* Returns the backing list as an unmodifiable {@code ObservableList}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public Routine toModelType() throws IllegalValueException {
}
final Name modelName = new Name(routineName);

final Set<Exercise> modelExercise = new HashSet<Exercise>(routineExercises);
final Set<Exercise> modelExercise = new HashSet<>(routineExercises);

Routine modelRoutine = new Routine(modelName);
for (Exercise exercise : modelExercise) {
Expand Down
157 changes: 157 additions & 0 deletions src/main/java/seedu/address/storage/JsonAdaptedSlot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package seedu.address.storage;

import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.model.person.Activity;
import seedu.address.model.person.Day;
import seedu.address.model.person.Duration;
import seedu.address.model.person.Exercise;
import seedu.address.model.person.Lesson;
import seedu.address.model.person.Name;
import seedu.address.model.person.Routine;
import seedu.address.model.person.Slot;
import seedu.address.model.tag.Tag;

/**
* Jackson-friendly version of {@link Slot}.
*/
public class JsonAdaptedSlot {
public static final String TYPE_ROUTINE = "routine";
public static final String TYPE_LESSON = "lesson";

public static final String MISSING_FIELD_MESSAGE_FORMAT = "Slot's %s field is missing!";

private final String activityName;
private final String type;
private final String day;
private final String duration;
private final List<JsonAdaptedTag> tagsForLesson = new ArrayList<>();
private final List<JsonAdaptedExercise> exercisesForRoutine = new ArrayList<>();

/**
* Constructs a {@code JsonAdaptedSlot} with the given slot details.
*/
@JsonCreator
public JsonAdaptedSlot(@JsonProperty("activityName") String activityName,
@JsonProperty("type") String type,
@JsonProperty("day") String day,
@JsonProperty("duration") String duration,
@JsonProperty("tagsForLesson") List<JsonAdaptedTag> tags,
@JsonProperty("exercisesForRoutine") List<JsonAdaptedExercise> exercises) {
this.activityName = activityName;
this.type = type;
this.day = day;
this.duration = duration;
if (type.equals(TYPE_LESSON)) {
if (tags != null) {
tagsForLesson.addAll(tags);
}
} else {
if (exercises != null) {
exercisesForRoutine.addAll(exercises);
}
}
}

/**
* Converts a given {@code Slot} into this class for Jackson use.
*/
public JsonAdaptedSlot(Slot source) {
activityName = source.getActivity().getName().fullName;
type = source.getActivity() instanceof Routine
? TYPE_ROUTINE
: TYPE_LESSON;
day = source.getDay().toString();
duration = source.getDuration().toString();
if (type.equals(TYPE_LESSON)) {
Lesson lesson = (Lesson) source.getActivity();
tagsForLesson.addAll(lesson.getTags()
.stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList()));
} else {
Routine routine = (Routine) source.getActivity();
exercisesForRoutine.addAll(routine.getExercises()
.stream()
.map(JsonAdaptedExercise::new)
.collect(Collectors.toList()));
}
}

/**
* Converts this Jackson-friendly adapted slot object into the model's {@code Slot} object.
*
* @throws IllegalValueException if there were any data constraints violated in the adapted exercise.
*/
public Slot toModelType() throws IllegalValueException {

if (activityName == null) {
throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
}
if (!Name.isValidName(activityName)) {
throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
}
if (Day.isUnknownDay(Day.getDayEnum(day))) {
throw new IllegalValueException(Day.MESSAGE_CONSTRAINTS);
}
if (!Duration.isValidDuration(duration)) {
throw new IllegalValueException(Duration.MESSAGE_CONSTRAINTS_FORMAT);
}

final Name modelName = new Name(activityName);

final Activity modelActivity;
if (type.equals(TYPE_LESSON)) {
final List<Tag> lessonTags = new ArrayList<>();
for (JsonAdaptedTag tag : tagsForLesson) {
lessonTags.add(tag.toModelType());
}
final Set<Tag> modelTags = new HashSet<>(lessonTags);
modelActivity = new Lesson(modelName, modelTags);
} else {
final List<Exercise> routineExercises = new ArrayList<>();
for (JsonAdaptedExercise exercise : exercisesForRoutine) {
routineExercises.add(exercise.toModelType());
}
final Set<Exercise> modelExercise = new HashSet<>(routineExercises);
Routine modelRoutine = new Routine(modelName);
for (Exercise exercise : modelExercise) {
modelRoutine.addExercise(exercise);
}
modelActivity = modelRoutine;
}

final Day modelDay = Day.getDayEnum(day);

final Duration modelDuration = parseDuration(duration);

return new Slot(modelActivity, modelDay, modelDuration);
}

private Duration parseDuration(String toParse) throws IllegalValueException {
String[] timeSplit = toParse.split("-");

int startHour = Integer.parseInt(timeSplit[0].substring(0, 2));
int startMinute = Integer.parseInt(timeSplit[0].substring(2, 4));
LocalTime startTime = LocalTime.of(startHour, startMinute);

int endHour = Integer.parseInt(timeSplit[1].substring(0, 2));
int endMinute = Integer.parseInt(timeSplit[1].substring(2, 4));
LocalTime endTime = LocalTime.of(endHour, endMinute);

if (!Duration.isValidDuration(startTime, endTime)) {
throw new IllegalValueException(Duration.MESSAGE_CONSTRAINTS_ORDER);
}

return new Duration(startTime, endTime);
}
}
Loading

0 comments on commit 5275d7d

Please sign in to comment.