diff --git a/src/planmysem/commands/AddCommand.java b/src/planmysem/commands/AddCommand.java index 16ecd0829..a09d7ec46 100644 --- a/src/planmysem/commands/AddCommand.java +++ b/src/planmysem/commands/AddCommand.java @@ -31,7 +31,6 @@ public class AddCommand extends Command { + " n/CS2113T Tutorial d/mon st/08:00 et/09:00 des/Topic: Sequence Diagram t/CS2113T " + "t/Tutorial r/normal"; - public static final String MESSAGE_SUCCESS_NO_CHANGE = "No slots were added."; public static final String MESSAGE_SUCCESS = "%1$s Slots added.\n\n%2$s"; public static final String MESSAGE_FAIL_OUT_OF_BOUNDS = "Date specified is out of bounds."; @@ -75,12 +74,8 @@ public CommandResult execute() { } } - if (dates.size() == 0) { - return new CommandResult(MESSAGE_SUCCESS_NO_CHANGE); - } else { - return new CommandResult(String.format(MESSAGE_SUCCESS, dates.size(), - craftSuccessMessage(days, slot))); - } + return new CommandResult(String.format(MESSAGE_SUCCESS, dates.size(), + craftSuccessMessage(days, slot))); } /** diff --git a/src/planmysem/commands/Command.java b/src/planmysem/commands/Command.java index 97753947d..5b68aace2 100644 --- a/src/planmysem/commands/Command.java +++ b/src/planmysem/commands/Command.java @@ -3,11 +3,12 @@ import static planmysem.ui.Gui.DISPLAYED_INDEX_OFFSET; import java.time.LocalDate; -import java.util.List; +import java.util.Map; import javafx.util.Pair; import planmysem.common.Messages; import planmysem.data.Planner; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; /** @@ -15,7 +16,7 @@ */ public abstract class Command { protected Planner planner; - protected List> relevantSlots; + protected Map> relevantSlots; private int targetIndex = -1; /** @@ -46,14 +47,15 @@ protected Command() { * @param slots used to generate summary * @return summary message for persons displayed */ - public static String getMessageForSlotsListShownSummary(List> slots) { + public static String getMessageForSlotsListShownSummary(Map> slots) { return String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, slots.size()); } /** * Supplies the data the command will operate on. */ - public void setData(Planner planner, List> slots) { + public void setData(Planner planner, Map> slots) { this.planner = planner; this.relevantSlots = slots; } @@ -62,9 +64,9 @@ public int getTargetIndex() { return targetIndex; } - public void setTargetIndex(int targetIndex) { - this.targetIndex = targetIndex; - } + // public void setTargetIndex(int targetIndex) { + // this.targetIndex = targetIndex; + // } /** @@ -72,15 +74,23 @@ public void setTargetIndex(int targetIndex) { * * @throws IndexOutOfBoundsException if the target index is out of bounds of the last viewed listing */ - protected List> getTargetSlots() throws IndexOutOfBoundsException { - return relevantSlots; - } + // protected Map> getTargetSlots() throws IndexOutOfBoundsException { + // return relevantSlots; + // } - protected Pair getTargetSlot(int index) throws IndexOutOfBoundsException { - return relevantSlots.get(index); - } + protected Pair> getTargetSlot() throws IndexOutOfBoundsException { + if (relevantSlots == null || relevantSlots.size() < targetIndex) { + throw new IndexOutOfBoundsException(); + } + + int count = 0; + for (Map.Entry> entry : relevantSlots.entrySet()) { + if (count == targetIndex - DISPLAYED_INDEX_OFFSET) { + return new Pair(entry.getKey(), entry.getValue()); + } + count++; + } - protected Pair getTargetSlot() throws IndexOutOfBoundsException { - return relevantSlots.get(targetIndex - DISPLAYED_INDEX_OFFSET); + throw new IndexOutOfBoundsException(); } } diff --git a/src/planmysem/commands/CommandResult.java b/src/planmysem/commands/CommandResult.java index 5da8160eb..4b45de3b0 100644 --- a/src/planmysem/commands/CommandResult.java +++ b/src/planmysem/commands/CommandResult.java @@ -1,10 +1,11 @@ package planmysem.commands; import java.time.LocalDate; -import java.util.List; +import java.util.Map; import java.util.Optional; import javafx.util.Pair; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; /** @@ -20,14 +21,14 @@ public class CommandResult { /** * The list of Slots that was produced by the command */ - private final List> slots; + private final Map> slots; public CommandResult(String feedbackToUser) { this.feedbackToUser = feedbackToUser; slots = null; } - public CommandResult(String feedbackToUser, List> slots) { + public CommandResult(String feedbackToUser, Map> slots) { this.feedbackToUser = feedbackToUser; this.slots = slots; } @@ -35,7 +36,7 @@ public CommandResult(String feedbackToUser, List>> getRelevantSlots() { + public Optional>> getRelevantSlots() { return Optional.ofNullable(slots); } diff --git a/src/planmysem/commands/DeleteCommand.java b/src/planmysem/commands/DeleteCommand.java index 025ad5ac5..6462012b7 100644 --- a/src/planmysem/commands/DeleteCommand.java +++ b/src/planmysem/commands/DeleteCommand.java @@ -1,7 +1,6 @@ package planmysem.commands; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -11,9 +10,8 @@ import planmysem.common.Messages; import planmysem.common.Utils; import planmysem.data.exception.IllegalValueException; -import planmysem.data.semester.Day; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; -import planmysem.data.slot.Slot; import planmysem.data.tag.Tag; /** @@ -33,11 +31,8 @@ public class DeleteCommand extends Command { + "\n\tExample 2: " + COMMAND_WORD + " 2"; - public static final String MESSAGE_SUCCESS_NO_CHANGE = "No Slots were deleted.\n\n%1$s"; public static final String MESSAGE_SUCCESS = "%1$s Slots deleted.\n\n%2$s\n%3$s"; - public static final String MESSAGE_FAIL_ILLEGAL_VALUE = MESSAGE_SUCCESS_NO_CHANGE - + " Illegal characters were detected."; private final Set tags = new HashSet<>(); @@ -59,70 +54,30 @@ public DeleteCommand(int index) { @Override public CommandResult execute() { - Map selectedSlots = new TreeMap<>(); + Map> selectedSlots = new TreeMap<>(); if (getTargetIndex() == -1) { - for (Map.Entry day : planner.getSemester().getDays().entrySet()) { - for (Slot slot : day.getValue().getSlots()) { - if (slot.getTags().containsAll(tags)) { - selectedSlots.put(LocalDateTime.of(day.getKey(), slot.getStartTime()), slot); - } - } - } + selectedSlots.putAll(planner.getSlots(tags)); + if (selectedSlots.size() == 0) { return new CommandResult(String.format(MESSAGE_SUCCESS_NO_CHANGE, Messages.craftSelectedMessage(tags))); } } else { try { - final Pair target = getTargetSlot(); - selectedSlots.put(LocalDateTime.of(target.getKey(), - target.getValue().getStartTime()), target.getValue()); - - if (!planner.containsSlot(target.getKey(), target.getValue())) { - return new CommandResult(Messages.MESSAGE_SLOT_NOT_IN_PLANNER); - } + final Pair> target = getTargetSlot(); + selectedSlots.put(target.getKey(), target.getValue()); } catch (IndexOutOfBoundsException ie) { return new CommandResult(Messages.MESSAGE_INVALID_SLOT_DISPLAYED_INDEX); } } // perform deletion of slots from the planner - for (Map.Entry slot: selectedSlots.entrySet()) { - planner.getSemester().removeSlot(slot.getKey().toLocalDate(), slot.getValue()); + for (Map.Entry> entry: selectedSlots.entrySet()) { + planner.removeSlot(entry.getKey(), entry.getValue().getValue()); } return new CommandResult(String.format(MESSAGE_SUCCESS, selectedSlots.size(), - Messages.craftSelectedMessage(tags), craftSuccessMessage(selectedSlots))); + Messages.craftSelectedMessage(tags), Messages.craftSelectedMessage("Deleted Slots:", selectedSlots))); } - - /** - * Craft success message. - */ - private String craftSuccessMessage(Map selectedSlots) { - StringBuilder sb = new StringBuilder(); - - sb.append("Deleted Slots: "); - sb.append("\n"); - - int count = 1; - for (Map.Entry editedSlot : selectedSlots.entrySet()) { - sb.append(count); - sb.append(".\t"); - sb.append(editedSlot.getValue().getName().toString()); - sb.append(", "); - sb.append(editedSlot.getKey().toLocalDate().toString()); - sb.append(" "); - sb.append(editedSlot.getKey().toLocalTime().toString()); - sb.append(", "); - sb.append(planner.getSemester().getDays().get(editedSlot.getKey().toLocalDate()).getType()); - sb.append(", "); - sb.append(editedSlot.getKey().getDayOfWeek().toString()); - count++; - sb.append("\n"); - } - - return sb.toString(); - } - } diff --git a/src/planmysem/commands/EditCommand.java b/src/planmysem/commands/EditCommand.java index 7857c4894..d85e10146 100644 --- a/src/planmysem/commands/EditCommand.java +++ b/src/planmysem/commands/EditCommand.java @@ -1,18 +1,18 @@ package planmysem.commands; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.StringJoiner; import java.util.TreeMap; import javafx.util.Pair; import planmysem.common.Messages; import planmysem.common.Utils; import planmysem.data.exception.IllegalValueException; -import planmysem.data.semester.Semester; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; import planmysem.data.tag.Tag; @@ -90,10 +90,10 @@ public EditCommand(int index, String name, LocalDate date, LocalTime startTime, @Override public CommandResult execute() { - Map selectedSlots = new TreeMap<>(); + final Map> selectedSlots = new TreeMap<>(); if (getTargetIndex() == -1) { - planner.getSlots(tags); + selectedSlots.putAll(planner.getSlots(tags)); if (selectedSlots.size() == 0) { return new CommandResult(String.format(MESSAGE_SUCCESS_NO_CHANGE, @@ -101,40 +101,47 @@ public CommandResult execute() { } } else { try { - final Pair target = getTargetSlot(); - selectedSlots.put(LocalDateTime.of(target.getKey(), - target.getValue().getStartTime()), target.getValue()); - if (!planner.containsSlot(target.getKey(), target.getValue())) { - return new CommandResult(Messages.MESSAGE_SLOT_NOT_IN_PLANNER); - } + final Pair> target = getTargetSlot(); + selectedSlots.put(target.getKey(), target.getValue()); } catch (IndexOutOfBoundsException ie) { return new CommandResult(Messages.MESSAGE_INVALID_SLOT_DISPLAYED_INDEX); } } - for (Map.Entry entry : selectedSlots.entrySet()) { + // Need to craft success message earlier to get original instead of edited Slots + String successMessage = craftSuccessMessage(selectedSlots); + + for (Map.Entry> entry : selectedSlots.entrySet()) { try { - planner.editSlot(entry.getKey().toLocalDate(), entry.getValue(), date, + planner.editSlot(entry.getKey(), entry.getValue().getValue(), date, startTime, duration, name, location, description, newTags); } catch (IllegalValueException ive) { return new CommandResult(MESSAGE_FAIL_ILLEGAL_VALUE); - } catch (Semester.DateNotFoundException dnfe) { - return new CommandResult(Messages.MESSAGE_SLOT_NOT_IN_PLANNER); } } return new CommandResult(String.format(MESSAGE_SUCCESS, selectedSlots.size(), - Messages.craftSelectedMessage(tags), craftSuccessMessage(selectedSlots))); + Messages.craftSelectedMessage(tags), successMessage)); } /** * Craft success message. */ - private String craftSuccessMessage(Map selectedSlots) { + public String craftSuccessMessage(Map> selectedSlots) { StringBuilder sb = new StringBuilder(); sb.append("Details Edited: "); + if (name != null) { + sb.append("\nName: "); + sb.append("\""); + if ("".equals(name)) { + sb.append("null"); + } else { + sb.append(name); + } + sb.append("\""); + } if (startTime != null) { sb.append("\nStart Time: "); sb.append("\""); @@ -167,38 +174,23 @@ private String craftSuccessMessage(Map selectedSlot } sb.append("\""); } + if (newTags.size() > 0) { + sb.append("\nTags: "); + StringJoiner sj = new StringJoiner(", "); + + for (Tag tag : newTags) { + StringBuilder sb2 = new StringBuilder(); + sb2.append("\""); + sb2.append(tag); + sb2.append("\""); + sj.add(sb2.toString()); + } + sb.append(sj.toString()); + } sb.append("\n\n"); - sb.append("Edited Slots: "); - sb.append("\n"); - - sb.append(craftSelectedMessage(selectedSlots)); - return sb.toString(); - } - - /** - * Craft success message. - */ - private String craftSelectedMessage(Map selectedSlots) { - StringBuilder sb = new StringBuilder(); - - int count = 1; - for (Map.Entry editedSlot : selectedSlots.entrySet()) { - sb.append(count); - sb.append(".\t"); - sb.append(editedSlot.getValue().getName().toString()); - sb.append(", "); - sb.append(editedSlot.getKey().toLocalDate().toString()); - sb.append(" "); - sb.append(editedSlot.getKey().toLocalTime().toString()); - sb.append(", "); - sb.append(planner.getSemester().getDays().get(editedSlot.getKey().toLocalDate()).getType()); - sb.append(", "); - sb.append(editedSlot.getKey().getDayOfWeek().toString()); - count++; - sb.append("\n"); - } + sb.append(Messages.craftSelectedMessage("Edited Slots:", selectedSlots)); return sb.toString(); } diff --git a/src/planmysem/commands/FindCommand.java b/src/planmysem/commands/FindCommand.java index 027f718fb..ea76f6fa5 100644 --- a/src/planmysem/commands/FindCommand.java +++ b/src/planmysem/commands/FindCommand.java @@ -1,14 +1,15 @@ package planmysem.commands; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.regex.Pattern; import javafx.util.Pair; +import planmysem.common.Messages; import planmysem.data.semester.Day; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; import planmysem.data.slot.Slot; import planmysem.data.tag.Tag; @@ -32,92 +33,38 @@ public class FindCommand extends Command { private final String keyword; private final boolean isFindByName; - public FindCommand(String name, String tag ) { + public FindCommand(String name, String tag) { this.keyword = (name == null) ? tag.trim() : name.trim(); this.isFindByName = (name != null); } @Override public CommandResult execute() { - final List> relevantSlots = new ArrayList<>(); - List matchedSlots = new ArrayList<>(); - LocalDate date; + Map> selectedSlots = new TreeMap<>(); - for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { - for (Slot slots : entry.getValue().getSlots()) { + for (Map.Entry entry : planner.getAllDays().entrySet()) { + for (Slot slot : entry.getValue().getSlots()) { if (isFindByName) { - if (Pattern.matches(".*" + keyword + ".*", slots.getName().value)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + if (Pattern.matches(".*" + keyword + ".*", slot.getName().value)) { + selectedSlots.put(entry.getKey(), new Pair<>(entry.getValue(), slot)); } } else { - Set tagSet = slots.getTags(); + Set tagSet = slot.getTags(); for (Tag tag : tagSet) { if (Pattern.matches(".*" + keyword + ".*", tag.value)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + selectedSlots.put(entry.getKey(), new Pair<>(entry.getValue(), slot)); } } } } } - if (matchedSlots.isEmpty()) { + if (selectedSlots.isEmpty()) { return new CommandResult(MESSAGE_SUCCESS_NONE); } - setData(this.planner, relevantSlots); + setData(planner, selectedSlots); - return new CommandResult(String.format(MESSAGE_SUCCESS, matchedSlots.size(), - craftSuccessMessage(relevantSlots))); -// final List> relevantSlots = new ArrayList<>(); -// List matchedSlots = new ArrayList<>(); -// LocalDate date; -// -// for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { -// for (Slot slots : entry.getValue().getSlots()) { -// if (Pattern.matches(".*" + keyword + ".*", slots.getName().value)) { -// matchedSlots.add(slots); -// date = entry.getKey(); -// relevantSlots.add(new Pair<>(date, slots)); -// } -// } -// } -// -// if (matchedSlots.isEmpty()) { -// return new CommandResult(MESSAGE_SUCCESS_NONE); -// } -// setData(this.planner, relevantSlots); -// -// return new CommandResult(String.format(MESSAGE_SiUCCESS, matchedSlots.size(), -// craftSuccessMessage(rele - } - - /** - * Craft success message. - */ - private String craftSuccessMessage(List> result) { - int count = 1; - StringBuilder sb = new StringBuilder(); - - for (Pair pair : result) { - sb.append("\n"); - sb.append(count + ".\t"); - sb.append("Name: "); - sb.append(pair.getValue().getName().toString()); - sb.append(",\n\t"); - sb.append("Date: "); - sb.append(pair.getKey().toString()); - sb.append(",\n\t"); - sb.append("Start Time: "); - sb.append(pair.getValue().getStartTime()); - sb.append("\n\t"); - sb.append("Tags: "); - sb.append(pair.getValue().getTags()); - sb.append("\n"); - count++; - } - return sb.toString(); + return new CommandResult(String.format(MESSAGE_SUCCESS, selectedSlots.size(), + Messages.craftSelectedMessage(selectedSlots))); } } diff --git a/src/planmysem/commands/ListCommand.java b/src/planmysem/commands/ListCommand.java index 3f898693d..a024ca4a2 100644 --- a/src/planmysem/commands/ListCommand.java +++ b/src/planmysem/commands/ListCommand.java @@ -1,13 +1,14 @@ package planmysem.commands; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import javafx.util.Pair; +import planmysem.common.Messages; import planmysem.data.semester.Day; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; import planmysem.data.slot.Slot; import planmysem.data.tag.Tag; @@ -38,67 +39,35 @@ public ListCommand(String name, String tag) { } @Override public CommandResult execute() { - final List> relevantSlots = new ArrayList<>(); - List matchedSlots = new ArrayList<>(); - LocalDate date; + Map> selectedSlots = new TreeMap<>(); - for (Map.Entry entry : planner.getSemester().getDays().entrySet()) { - for (Slot slots : entry.getValue().getSlots()) { + for (Map.Entry entry : planner.getAllDays().entrySet()) { + for (Slot slot : entry.getValue().getSlots()) { if (isListByName) { - if (slots.getName().value.equalsIgnoreCase(keyword)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + if (slot.getName().value.equalsIgnoreCase(keyword)) { + selectedSlots.put(entry.getKey(), new Pair<>(entry.getValue(), slot)); } } else { - Set tagSet = slots.getTags(); + Set tagSet = slot.getTags(); for (Tag tag : tagSet) { + // if (slot.getTags().contains(keyword)) if (tag.value.equalsIgnoreCase(keyword)) { - matchedSlots.add(slots); - date = entry.getKey(); - relevantSlots.add(new Pair<>(date, slots)); + selectedSlots.put(entry.getKey(), new Pair<>(entry.getValue(), slot)); } } } } } - if (matchedSlots.isEmpty()) { + if (selectedSlots.isEmpty()) { return new CommandResult(MESSAGE_SUCCESS_NONE); } setData(this.planner, relevantSlots); - return new CommandResult(String.format(MESSAGE_SUCCESS, matchedSlots.size(), - craftSuccessMessage(relevantSlots))); + return new CommandResult(String.format(MESSAGE_SUCCESS, selectedSlots.size(), + Messages.craftListMessage(selectedSlots))); } - - /** - * Craft success message. - */ - private String craftSuccessMessage(List> result) { - int count = 1; - StringBuilder sb = new StringBuilder(); - - for (Pair pair : result) { - sb.append("\n"); - sb.append(count + ".\t"); - sb.append("Name: "); - sb.append(pair.getValue().getName().toString()); - sb.append(",\n\t"); - sb.append("Date: "); - sb.append(pair.getKey().toString()); - sb.append(",\n\t"); - sb.append("Start Time: "); - sb.append(pair.getValue().getStartTime()); - sb.append("\n\t"); - sb.append("Tags: "); - sb.append(pair.getValue().getTags()); - sb.append("\n"); - count++; - } - return sb.toString(); - } } diff --git a/src/planmysem/common/Messages.java b/src/planmysem/common/Messages.java index e338992e5..8ad408670 100644 --- a/src/planmysem/common/Messages.java +++ b/src/planmysem/common/Messages.java @@ -1,7 +1,12 @@ package planmysem.common; +import java.time.LocalDate; +import java.util.Map; import java.util.Set; +import javafx.util.Pair; +import planmysem.data.semester.ReadOnlyDay; +import planmysem.data.slot.ReadOnlySlot; import planmysem.data.tag.Tag; /** @@ -53,5 +58,77 @@ public static String craftSelectedMessage(Set tags) { return sb.toString(); } + /** + * Craft selected message with header. + */ + public static String craftSelectedMessage(String header, + Map> selectedSlots) { + StringBuilder sb = new StringBuilder(); + sb.append(header); + sb.append("\n"); + + return sb.toString() + getSelectedMessage(selectedSlots); + } + + /** + * Craft selected message without header. + */ + public static String craftSelectedMessage(Map> selectedSlots) { + return getSelectedMessage(selectedSlots); + } + /** + * Craft list message. + */ + public static String craftListMessage(Map> selectedSlots) { + StringBuilder sb = new StringBuilder(); + + int count = 1; + for (Map.Entry> entry : selectedSlots.entrySet()) { + sb.append("\n"); + sb.append(count + ".\t"); + sb.append("Name: "); + sb.append(entry.getValue().getValue().getName().toString()); + sb.append(",\n\t"); + sb.append("Date: "); + sb.append(entry.getKey().toString()); + sb.append(",\n\t"); + sb.append("Start Time: "); + sb.append(entry.getValue().getValue().getStartTime()); + sb.append("\n\t"); + sb.append("Tags: "); + sb.append(entry.getValue().getValue().getTags()); + sb.append("\n"); + count++; + } + return sb.toString(); + } + + /** + * Craft selected message. + */ + private static String getSelectedMessage(Map> selectedSlots) { + StringBuilder sb = new StringBuilder(); + + int count = 1; + for (Map.Entry> entry : selectedSlots.entrySet()) { + sb.append(count); + sb.append(".\t"); + sb.append(entry.getValue().getValue().getName()); + sb.append(", "); + sb.append(entry.getKey()); + sb.append(" "); + sb.append(entry.getValue().getValue().getStartTime()); + sb.append(", "); + sb.append(entry.getValue().getKey().getType()); + sb.append(", "); + sb.append(entry.getKey().getDayOfWeek().toString()); + count++; + sb.append("\n"); + } + + return sb.toString(); + } } diff --git a/src/planmysem/common/Utils.java b/src/planmysem/common/Utils.java index 423167d69..411918b51 100644 --- a/src/planmysem/common/Utils.java +++ b/src/planmysem/common/Utils.java @@ -119,10 +119,13 @@ public static int parseDay(String unknown) { } /** - * Parse String LocalDate. + * Parse String to LocalDate. */ public static LocalDate parseDate(String date) { - if (date != null && DATE_FORMAT.matcher(date).matches()) { + if (date == null) { + return null; + } + if (DATE_FORMAT.matcher(date).matches()) { return LocalDate.parse(date, DateTimeFormatter.ofPattern("d-MM-yyyy")); } else if (DATE_FORMAT_NO_YEAR.matcher(date).matches()) { return LocalDate.parse(date + "-" + Year.now().getValue(), DateTimeFormatter.ofPattern("d-MM-yyyy")); @@ -131,6 +134,13 @@ public static LocalDate parseDate(String date) { return null; } + /** + * Parse LocalDate to String. + */ + public static String parseDate(LocalDate date) { + return date.format(DateTimeFormatter.ofPattern("d-MM-yyyy")); + } + /** * Parse String to 12 hour or 24 hour time format. */ @@ -177,21 +187,21 @@ public static Set parseTags(Set tags) throws IllegalValueException /** - * Get the time difference between two LocalTimes + * Get the time difference between two LocalTimes in minutes. */ public static int getDuration(LocalTime startTime, LocalTime endTime) { return (int) MINUTES.between(startTime, endTime); } /** - * Get the end time of a time after a duration + * Get the end time of a time after a duration. */ public static LocalTime getEndTime(LocalTime time, int duration) { return time.plusMinutes(duration); } /** - * Get the nearest date to a type of day from today + * Get the nearest date to a type of day from today. */ public static LocalDate getNearestDayOfWeek(LocalDate date, int day) { return date.with(TemporalAdjusters.next(DayOfWeek.of(day))); diff --git a/src/planmysem/data/Planner.java b/src/planmysem/data/Planner.java index 843b6ca4b..0c3dd43fa 100644 --- a/src/planmysem/data/Planner.java +++ b/src/planmysem/data/Planner.java @@ -2,7 +2,6 @@ import java.time.DayOfWeek; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; import java.time.temporal.TemporalAdjusters; import java.time.temporal.WeekFields; @@ -11,8 +10,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.stream.Collectors; +import javafx.util.Pair; import planmysem.data.exception.IllegalValueException; import planmysem.data.semester.Day; import planmysem.data.semester.ReadOnlyDay; @@ -288,17 +289,9 @@ private static String[] getSemesterDetails(LocalDate date, HashMap getSlots(Set tags) { - return semester.getSlots(tags); - } - + // public void addDay(LocalDate date, Day day) throws Semester.DuplicateDayException { + // semester.addDay(date, day); + // } /** * Adds a slot to the Planner. @@ -308,16 +301,21 @@ public Day addSlot(LocalDate date, Slot slot) throws Semester.DateNotFoundExcept return semester.addSlot(date, slot); } + /** + * Removes a Slot in the Planner. + */ + public void removeSlot(LocalDate date, ReadOnlySlot slot) { + semester.removeSlot(date, slot); + } + /** * Edit specific slot within the planner. * - * @throws Semester.DateNotFoundException if a targetDate is not found in the semester. * @throws IllegalValueException if a targetDate is not found in the semester. */ public void editSlot(LocalDate targetDate, ReadOnlySlot targetSlot, LocalDate date, LocalTime startTime, int duration, String name, String location, - String description, Set tags) - throws Semester.DateNotFoundException, IllegalValueException { + String description, Set tags) throws IllegalValueException { semester.editSlot(targetDate, targetSlot, date, startTime, duration, name, location, description, tags); } @@ -381,6 +379,38 @@ public Semester getSemester() { return semester; } + /** + * gets all days in the Planner. + */ + public HashMap getAllDays() { + return semester.getDays(); + } + + /** + * gets specific day in the Planner. + */ + public Day getDay(LocalDate date) { + return getAllDays().get(date); + } + + /** + * gets all slots in the Planner containing all specified tags. + */ + public Map> getSlots(Set tags) { + final Map> selectedSlots = new TreeMap<>(); + + for (Map.Entry entry : getAllDays().entrySet()) { + for (Slot slot : entry.getValue().getSlots()) { + if (slot.getTags().containsAll(tags)) { + selectedSlots.put(entry.getKey(), new Pair<>(entry.getValue(), slot)); + } + } + } + + return selectedSlots; + } + + @Override public boolean equals(Object other) { return other == this // short circuit if same object diff --git a/src/planmysem/data/recurrence/Recurrence.java b/src/planmysem/data/recurrence/Recurrence.java index ee32581cd..d24abca20 100644 --- a/src/planmysem/data/recurrence/Recurrence.java +++ b/src/planmysem/data/recurrence/Recurrence.java @@ -124,6 +124,41 @@ public Set generateDates(Semester semester) { return result; } + /** + * Get set of dates where it is a specific DayOfWeek and is after a start date. + */ + private Set getDates(Set dates) { + final Set result = new HashSet<>(); + for (LocalDate d : dates) { + if (d.getDayOfWeek() == day) { + result.add(d); + } + } + + return result; + } + + /** + * Get set of dates where it is a specific DayOfWeek and is after a start date. + */ + private Set getDates(Set dates, LocalDate dateStart) { + final Set result = new HashSet<>(); + for (LocalDate d : dates) { + if (d.getDayOfWeek() == day && (d.isAfter(dateStart) || d.isEqual(dateStart))) { + result.add(d); + } + } + + return result; + } + + /** + * Get date. + */ + public LocalDate getDate() { + return date; + } + @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -155,32 +190,4 @@ public int hashCode() { } return hashCode + day.hashCode() + date.hashCode(); } - - /** - * Get set of dates where it is a specific DayOfWeek and is after a start date. - */ - private Set getDates(Set dates) { - final Set result = new HashSet<>(); - for (LocalDate d : dates) { - if (d.getDayOfWeek() == day) { - result.add(d); - } - } - - return result; - } - - /** - * Get set of dates where it is a specific DayOfWeek and is after a start date. - */ - private Set getDates(Set dates, LocalDate dateStart) { - final Set result = new HashSet<>(); - for (LocalDate d : dates) { - if (d.getDayOfWeek() == day && (d.isAfter(dateStart) || d.isEqual(dateStart))) { - result.add(d); - } - } - - return result; - } } diff --git a/src/planmysem/data/semester/Semester.java b/src/planmysem/data/semester/Semester.java index 3c18db98e..004e48543 100644 --- a/src/planmysem/data/semester/Semester.java +++ b/src/planmysem/data/semester/Semester.java @@ -139,10 +139,7 @@ public void removeSlot(LocalDate date, ReadOnlySlot slot) { */ public void editSlot(LocalDate targetDate, ReadOnlySlot targetSlot, LocalDate date, LocalTime startTime, int duration, String name, String location, String description, Set tags) - throws DateNotFoundException, IllegalValueException { - if (targetDate == null || (targetDate.isBefore(startDate) || targetDate.isAfter(endDate))) { - throw new DateNotFoundException(); - } + throws IllegalValueException { Slot editingSlot = days.get(targetDate).getSlots().stream() .filter(s -> s.equals(targetSlot)).findAny().orElse(null); diff --git a/src/planmysem/logic/Logic.java b/src/planmysem/logic/Logic.java index 5c43625ed..56b5f9df6 100644 --- a/src/planmysem/logic/Logic.java +++ b/src/planmysem/logic/Logic.java @@ -1,8 +1,7 @@ package planmysem.logic; import java.time.LocalDate; -import java.util.Collections; -import java.util.List; +import java.util.Map; import java.util.Optional; import javax.xml.bind.JAXBException; @@ -11,6 +10,7 @@ import planmysem.commands.Command; import planmysem.commands.CommandResult; import planmysem.data.Planner; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; import planmysem.parser.Parser; import planmysem.storage.StorageFile; @@ -25,7 +25,7 @@ public class Logic { /** * The list of Slots shown to the user most recently. */ - private List> lastShownSlots = Collections.emptyList(); + private Map> lastShownSlots; public Logic() throws Exception { setStorage(initializeStorage()); @@ -61,11 +61,11 @@ public String getStorageFilePath() { /** * Unmodifiable view of the current last shown list. */ - public List> getLastShownSlots() { + public Map> getLastShownSlots() { return lastShownSlots; } - protected void setLastShownSlots(List> slots) { + protected void setLastShownSlots(Map> slots) { lastShownSlots = slots; } @@ -99,7 +99,7 @@ private CommandResult execute(Command command) throws Exception { * Updates the {@link #lastShownSlots} if the result contains a list of Days. */ private void recordResult(CommandResult result) { - final Optional>> slots = result.getRelevantSlots(); + final Optional>> slots = result.getRelevantSlots(); if (slots.isPresent()) { lastShownSlots = slots.get(); } diff --git a/src/planmysem/parser/Parser.java b/src/planmysem/parser/Parser.java index 408c2c9ee..9ff033923 100644 --- a/src/planmysem/parser/Parser.java +++ b/src/planmysem/parser/Parser.java @@ -275,9 +275,6 @@ private Command prepareEdit(String args) { } else { String nd = getFirstInSet(arguments.get(PARAMETER_NEW_DATE)); LocalDate date = Utils.parseDate(nd); - if (date == null) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); - } try { return new EditCommand(index, name, date, startTime, duration, location, description, newTags); diff --git a/src/planmysem/ui/Formatter.java b/src/planmysem/ui/Formatter.java index 9c18f550f..473a91b62 100644 --- a/src/planmysem/ui/Formatter.java +++ b/src/planmysem/ui/Formatter.java @@ -1,10 +1,12 @@ package planmysem.ui; import java.time.LocalDate; -import java.util.ArrayList; import java.util.List; +import java.util.Map; import javafx.util.Pair; +import planmysem.common.Messages; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; /** @@ -70,14 +72,15 @@ public String format(String... messages) { /** * Formats the given list of slots for displaying to the user. */ - public String formatSlots(List> slots) { - final List formattedSlots = new ArrayList<>(); - - for (Pair pair : slots) { - formattedSlots.add(pair.getKey().toString() + ": " + pair.getValue().toString()); - } - - return format(asIndexedList(formattedSlots)); + public String formatSlots(Map> slots) { + // final List formattedSlots = new ArrayList<>(); + // + // for (Map.Entry> entry : slots.entrySet()) { + // formattedSlots.add(pair.getKey().toString() + ": " + pair.getValue().toString()); + // } + // + // return format(asIndexedList(formattedSlots)); + return Messages.craftListMessage(slots); } } diff --git a/src/planmysem/ui/MainWindow.java b/src/planmysem/ui/MainWindow.java index 08130860e..4fca1e385 100644 --- a/src/planmysem/ui/MainWindow.java +++ b/src/planmysem/ui/MainWindow.java @@ -1,7 +1,7 @@ package planmysem.ui; import java.time.LocalDate; -import java.util.List; +import java.util.Map; import java.util.Optional; import javafx.fxml.FXML; @@ -11,6 +11,7 @@ import planmysem.commands.CommandResult; import planmysem.commands.ExitCommand; import planmysem.common.Messages; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.ReadOnlySlot; import planmysem.logic.Logic; @@ -84,7 +85,7 @@ public void clearOutputConsole() { */ public void displayResult(CommandResult result) { clearOutputConsole(); - final Optional>> resultDays = result.getRelevantSlots(); + final Optional>> resultDays = result.getRelevantSlots(); if (resultDays.isPresent()) { display(resultDays.get()); } @@ -103,7 +104,7 @@ public void displayWelcomeMessage(String version, String storageFilePath) { * Displays the list of slots in the output display area, formatted as an indexed list. * Private contact details are hidden. */ - private void display(List> slots) { + private void display(Map> slots) { // TODO: rename function call when AddressBook is fully removed from project display(new Formatter().formatSlots(slots)); } diff --git a/test/java/planmysem/common/UtilsTest.java b/test/java/planmysem/common/UtilsTest.java index 12d8e39b4..82d34399a 100644 --- a/test/java/planmysem/common/UtilsTest.java +++ b/test/java/planmysem/common/UtilsTest.java @@ -3,7 +3,11 @@ import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static planmysem.common.Utils.getDuration; +import static planmysem.common.Utils.getEndTime; +import static planmysem.common.Utils.getNearestDayOfWeek; +import java.time.LocalDate; import java.time.LocalTime; import java.util.ArrayList; import java.util.Arrays; @@ -203,6 +207,30 @@ public void parse_tags_unsuccessful() { assertEquals(tags, null); } + @Test + public void parse_get_duration_successful() { + LocalTime startTime = LocalTime.now(); + LocalTime endTime = startTime.plusMinutes(60); + + assertEquals(getDuration(startTime, endTime), 60); + } + + @Test + public void parse_get_end_time_successful() { + LocalTime startTime = LocalTime.now(); + LocalTime endTime = startTime.plusMinutes(60); + + assertEquals(getEndTime(startTime, 60), endTime); + } + + @Test + public void parse_get_nearest_day_of_week_successful() { + LocalDate date = LocalDate.of(2019, 1, 1); + LocalDate nearestMonday = LocalDate.of(2019, 1, 7); + + assertEquals(getNearestDayOfWeek(date, 1), nearestMonday); + } + private void assertAreUnique(Object... objects) { assertTrue(Utils.elementsAreUnique(Arrays.asList(objects))); } diff --git a/test/java/planmysem/data/PlannerTest.java b/test/java/planmysem/data/PlannerTest.java index 654b79633..45c725126 100644 --- a/test/java/planmysem/data/PlannerTest.java +++ b/test/java/planmysem/data/PlannerTest.java @@ -62,7 +62,7 @@ private void assertSameSemester(Semester generatedSemester, Semester expectedSem /** * A utility class to generate test data. */ - class TestDataHelper { + public class TestDataHelper { /** * Generates a Semester from the given date diff --git a/test/java/planmysem/logic/LogicTest.java b/test/java/planmysem/logic/LogicTest.java index d72c5fdfd..f9e692581 100644 --- a/test/java/planmysem/logic/LogicTest.java +++ b/test/java/planmysem/logic/LogicTest.java @@ -2,18 +2,25 @@ import static junit.framework.TestCase.assertEquals; -import static planmysem.common.Messages.*; - +import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static planmysem.common.Messages.MESSAGE_INVALID_COMMAND_FORMAT_ADDITIONAL; +import static planmysem.common.Messages.MESSAGE_INVALID_DATE; +import static planmysem.common.Messages.MESSAGE_INVALID_MULTIPLE_PARAMS; +import static planmysem.common.Messages.MESSAGE_INVALID_SLOT_DISPLAYED_INDEX; +import static planmysem.common.Messages.MESSAGE_INVALID_TIME; + +import java.time.Clock; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; -import java.time.format.DateTimeFormatter; +import java.time.ZoneOffset; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.StringJoiner; +import java.util.TreeMap; import javafx.util.Pair; import org.junit.Before; @@ -24,13 +31,17 @@ import planmysem.commands.ClearCommand; import planmysem.commands.CommandResult; import planmysem.commands.DeleteCommand; -import planmysem.commands.FindCommand; -import planmysem.commands.ListCommand; import planmysem.commands.EditCommand; import planmysem.commands.ExitCommand; +import planmysem.commands.FindCommand; import planmysem.commands.HelpCommand; +import planmysem.commands.ListCommand; +import planmysem.common.Messages; +import planmysem.common.Utils; import planmysem.data.Planner; +import planmysem.data.recurrence.Recurrence; import planmysem.data.semester.Day; +import planmysem.data.semester.ReadOnlyDay; import planmysem.data.slot.Description; import planmysem.data.slot.Location; import planmysem.data.slot.Name; @@ -54,9 +65,16 @@ public class LogicTest { @Before public void setup() throws Exception { storageFile = new StorageFile(temporaryFolder.newFile("testSaveFile.txt").getPath()); - planner = new Planner(); + planner = createPlanner(); storageFile.save(planner); logic = new Logic(storageFile, planner); + Instant.now(Clock.fixed( + Instant.parse("2019-02-02T10:00:00Z"), + ZoneOffset.UTC)); + } + + private Planner createPlanner() { + return new Planner(Planner.generateSemester(LocalDate.of(2019, 1, 14))); } @Test @@ -64,7 +82,7 @@ public void constructor() { //Constructor is called in the setup() method which executes before every test, no need to call it here again. //Confirm the last shown list is empty - assertEquals(Collections.emptyList(), logic.getLastShownSlots()); + assertEquals(null, logic.getLastShownSlots()); } @Test @@ -92,12 +110,17 @@ public void execute_exit() throws Exception { @Test public void execute_clear() throws Exception { + Planner expectedPlanner = createPlanner(); TestDataHelper helper = new TestDataHelper(); - planner.addSlot(LocalDate.now(), helper.generateSlot(1)); - planner.addSlot(LocalDate.now(), helper.generateSlot(2)); - planner.addSlot(LocalDate.now(), helper.generateSlot(3)); + planner.addSlot(LocalDate.of(2019, 2, 1), helper.generateSlot(1)); + planner.addSlot(LocalDate.of(2019, 2, 1), helper.generateSlot(2)); + planner.addSlot(LocalDate.of(2019, 2, 1), helper.generateSlot(3)); - assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new Planner(), false, Collections.emptyList()); + assertCommandBehavior("clear", + ClearCommand.MESSAGE_SUCCESS, + expectedPlanner, + false, + null); } /** @@ -130,27 +153,122 @@ public void execute_add_invalidSlotData() throws Exception { } @Test - public void execute_add_successful() throws Exception { - // setup expectations + public void execute_add_by_date_successful() throws Exception { + // item to be added + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + LocalDate dateToBeAdded = LocalDate.of(2019, 2, 2); + + // expectation + Planner expectedPlanner = createPlanner(); + expectedPlanner.addSlot(dateToBeAdded, slotToBeAdded); + Map days = new TreeMap<>(); + days.put(dateToBeAdded, expectedPlanner.getDay(dateToBeAdded)); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(slotToBeAdded, dateToBeAdded, ""), + String.format(AddCommand.MESSAGE_SUCCESS, + 1, + AddCommand.craftSuccessMessage(days, slotToBeAdded)), + expectedPlanner, + false, + null); + } + + @Test + public void execute_add_by_day_successful() throws Exception { + // because adding by day takes the nearest day, the planner has to be changed to be in respects to the current system date. + // item to be added TestDataHelper helper = new TestDataHelper(); Slot slotToBeAdded = helper.slotOne(); - LocalDate dateToBeAdded = LocalDate.now(); - HashMap days = new HashMap<>(); - days.put(dateToBeAdded, planner.getSemester().getDays().get(dateToBeAdded)); + int dayToBeAdded = LocalDate.now().getDayOfWeek().getValue(); + LocalDate dateToBeAdded = Utils.getNearestDayOfWeek(LocalDate.now(), dayToBeAdded); - Planner expectedPlanner = new Planner(); + // expectation + Planner expectedPlanner = createPlanner(); expectedPlanner.addSlot(dateToBeAdded, slotToBeAdded); + Map days = new TreeMap<>(); + days.put(dateToBeAdded, expectedPlanner.getDay(dateToBeAdded)); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(slotToBeAdded, dayToBeAdded, ""), + String.format(AddCommand.MESSAGE_SUCCESS, + 1, + AddCommand.craftSuccessMessage(days, slotToBeAdded)), + expectedPlanner, + false, + null); + } + + @Test + public void execute_add_by_date_multiple_successful() throws Exception { + // item to be added + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + LocalDate dateToBeAdded = LocalDate.of(2019, 2, 2); + + // expectation + Planner expectedPlanner = createPlanner(); + Recurrence recurrence = new Recurrence(new HashSet<>(Arrays.asList("normal")), dateToBeAdded); + Map days = new TreeMap<>(); + for (LocalDate date : recurrence.generateDates(expectedPlanner.getSemester())) { + expectedPlanner.addSlot(date, slotToBeAdded); + days.put(date, expectedPlanner.getDay(date)); + } + + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(slotToBeAdded, dateToBeAdded, "r/normal"), + String.format(AddCommand.MESSAGE_SUCCESS, + days.size(), + AddCommand.craftSuccessMessage(days, slotToBeAdded)), + expectedPlanner, + false, + null); + } + + @Test + public void execute_add_by_day_multiple_successful() throws Exception { + // item to be added + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + int dayToBeAdded = LocalDate.of(2019, 2, 2).getDayOfWeek().getValue(); + LocalDate dateToBeAdded = Utils.getNearestDayOfWeek(LocalDate.now(), dayToBeAdded); + + // expectation + Planner expectedPlanner = createPlanner(); + Recurrence recurrence = new Recurrence(new HashSet<>(Arrays.asList("normal")), dayToBeAdded); + Map days = new TreeMap<>(); + for (LocalDate date : recurrence.generateDates(expectedPlanner.getSemester())) { + expectedPlanner.addSlot(date, slotToBeAdded); + days.put(date, expectedPlanner.getDay(date)); + } + // execute command and verify result - assertCommandBehavior(helper.generateAddCommand(dateToBeAdded, slotToBeAdded), - String.format(AddCommand.MESSAGE_SUCCESS, 1, AddCommand.craftSuccessMessage(days, slotToBeAdded)), + assertCommandBehavior(helper.generateAddCommand(slotToBeAdded, dayToBeAdded, "r/normal"), + String.format(AddCommand.MESSAGE_SUCCESS, + days.size(), + AddCommand.craftSuccessMessage(days, slotToBeAdded)), expectedPlanner, false, - Collections.emptyList()); + null); + } + + @Test + public void execute_add_unsuccessful() throws Exception { + // item to be added + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + LocalDate dateToBeAdded = LocalDate.of(1999, 1, 1); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(slotToBeAdded, dateToBeAdded, ""), + AddCommand.MESSAGE_FAIL_OUT_OF_BOUNDS); } /** - * Test delete command + * Test edit command */ @Test @@ -166,27 +284,66 @@ public void execute_edit_invalidArgsFormat() throws Exception { "e nl/COM2 04-01", expectedMessage); } - // @Test - // public void execute_delete_successful() throws Exception { - // // setup expectations - // TestDataHelper helper = new TestDataHelper(); - // Slot slotToBeAdded = helper.slotOne(); - // LocalDate dateToBeAdded = LocalDate.now(); - // HashMap days = new HashMap<>(); - // days.put(dateToBeAdded, planner.getSemester().getDays().get(dateToBeAdded)); - // - // Planner expectedPlanner = new Planner(); - // expectedPlanner.addSlot(dateToBeAdded, slotToBeAdded); - // expectedPlanner.getSemester().removeSlot(dateToBeAdded, slotToBeAdded); - // planner.addSlot(dateToBeAdded, slotToBeAdded); - // - // // execute command and verify result - // assertCommandBehavior(helper.generateAddCommand(dateToBeAdded, slotToBeAdded), - // String.format(AddCommand.MESSAGE_SUCCESS, 1, AddCommand.craftSuccessMessage(days, slotToBeAdded)), - // expectedPlanner, - // false, - // Collections.emptyList()); - // } + @Test + public void execute_edit_successful() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + LocalDate dateToBeAdded = LocalDate.of(2019, 2, 2); + planner.addSlot(dateToBeAdded, new Slot(slotToBeAdded)); + Map> selectedSlots = new TreeMap<>(); + selectedSlots.put(dateToBeAdded, + new Pair(planner.getDay(dateToBeAdded), new Slot(slotToBeAdded))); + + // setup expectations + Planner expectedPlanner = createPlanner(); + expectedPlanner.addSlot(dateToBeAdded, slotToBeAdded); + + // create tags + Set rawTags = new HashSet<>(); + rawTags.add("CS2113T"); + Set tags = Utils.parseTags(rawTags); + + Set rawNewTags = new HashSet<>(); + rawNewTags.add("CS2101"); + Set newTags = Utils.parseTags(rawNewTags); + + expectedPlanner.editSlot(dateToBeAdded, slotToBeAdded, null, LocalTime.of(4, 0), 60, + "test", "testlo", "testdes", newTags); + + // Just to generate the crafted message in this case. + EditCommand ec = new EditCommand("test", LocalTime.of(4, 0), 60, + "testlo", "testdes", rawTags, rawNewTags); + + // execute command and verify result + assertCommandBehavior("edit t/CS2113T nt/CS2101 nn/test nl/testlo ndes/testdes nst/04:00 net/60", + String.format(EditCommand.MESSAGE_SUCCESS, selectedSlots.size(), + Messages.craftSelectedMessage(tags), ec.craftSuccessMessage(selectedSlots)), + expectedPlanner, + false, + null); + } + + @Test + public void execute_edit_no_change_successful() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Set rawTags = new HashSet<>(); + rawTags.add("someTagThatDoesNotExist"); + Set tags = Utils.parseTags(rawTags); + + assertCommandBehavior("edit t/someTagThatDoesNotExist n/test", + String.format(EditCommand.MESSAGE_SUCCESS_NO_CHANGE, + Messages.craftSelectedMessage(tags))); + } + + @Test + public void execute_edit_invalid_slot_displayed_unsuccessful() throws Exception { + assertCommandBehavior("edit 100", MESSAGE_INVALID_SLOT_DISPLAYED_INDEX); + } + +// @Test +// public void execute_edit_out_of_bound_unsuccessful() throws Exception { +// assertCommandBehavior("edit 100", MESSAGE_INVALID_SLOT_DISPLAYED_INDEX); +// } /** * Test delete command @@ -205,6 +362,52 @@ public void execute_delete_invalidArgsFormat() throws Exception { "d wrong", expectedMessage); } + @Test + public void execute_delete_successful() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Slot slotToBeAdded = helper.slotOne(); + LocalDate dateToBeAdded = LocalDate.of(2019, 2, 2); + planner.addSlot(dateToBeAdded, slotToBeAdded); + Map> selectedSlots = new TreeMap<>(); + selectedSlots.put(dateToBeAdded, + new Pair(planner.getDay(dateToBeAdded), slotToBeAdded)); + + // setup expectations + Planner expectedPlanner = createPlanner(); + expectedPlanner.addSlot(dateToBeAdded, slotToBeAdded); + expectedPlanner.getSemester().removeSlot(dateToBeAdded, slotToBeAdded); + + // execute command and verify result + assertCommandBehavior(helper.generateDeleteCommand(slotToBeAdded), + String.format(DeleteCommand.MESSAGE_SUCCESS, + 1, + Messages.craftSelectedMessage(slotToBeAdded.getTags()), + Messages.craftSelectedMessage("Deleted Slots:", selectedSlots)), expectedPlanner, + false, + null); + } + + @Test + public void execute_delete_no_change_successful() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Set rawTags = new HashSet<>(); + rawTags.add("someTagThatDoesNotExist"); + Set tags = Utils.parseTags(rawTags); + + assertCommandBehavior(helper.generateDeleteCommand(tags), + String.format(DeleteCommand.MESSAGE_SUCCESS_NO_CHANGE, + Messages.craftSelectedMessage(tags))); + } + + @Test + public void execute_delete_invalid_slot_displayed_unsuccessful() throws Exception { + assertCommandBehavior("delete 100", MESSAGE_INVALID_SLOT_DISPLAYED_INDEX); + } + + /** + * Test find command + */ + @Test public void execute_find_invalidArgsFormat() throws Exception { String expectedMessageSingle = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); @@ -231,7 +434,7 @@ public void execute_list_invalidArgsFormat() throws Exception { * @see #assertCommandBehavior(String, String, Planner, boolean, List) */ private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { - assertCommandBehavior(inputCommand, expectedMessage, planner,false, Collections.emptyList()); + assertCommandBehavior(inputCommand, expectedMessage, planner,false, null); } /** @@ -300,13 +503,13 @@ Slot generateSlot(int seed) throws Exception { } /** Generates the correct add command based on the person given */ - String generateAddCommand(LocalDate date, Slot s) { + String generateAddCommand(Slot s, LocalDate date, String recurrence) { StringJoiner cmd = new StringJoiner(" "); cmd.add("add"); cmd.add("n/" + s.getName()); - cmd.add("d/" + date.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))); + cmd.add("d/" + Utils.parseDate(date)); cmd.add("st/" + s.getStartTime()); cmd.add("et/" + s.getDuration()); if (s.getLocation() != null) { @@ -318,14 +521,95 @@ String generateAddCommand(LocalDate date, Slot s) { Set tags = s.getTags(); if (tags != null) { - for(Tag tag: tags){ + for(Tag tag : tags){ cmd.add("t/" + tag); } } + cmd.add(recurrence); + return cmd.toString(); } + /** Generates the correct add command based on the person given */ + String generateAddCommand(Slot s, int day, String recurrence) { + StringJoiner cmd = new StringJoiner(" "); + + cmd.add("add"); + + cmd.add("n/" + s.getName()); + cmd.add("d/" + day); + cmd.add("st/" + s.getStartTime()); + cmd.add("et/" + s.getDuration()); + if (s.getLocation() != null) { + cmd.add("l/" + s.getLocation()); + } + if (s.getDescription() != null) { + cmd.add("des/" + s.getDescription()); + } + + Set tags = s.getTags(); + if (tags != null) { + for(Tag tag : tags){ + cmd.add("t/" + tag); + } + } + + cmd.add(recurrence); + + return cmd.toString(); + } + + /** Generates the correct delete command based on tags */ + String generateDeleteCommand(Set tags) { + StringJoiner cmd = new StringJoiner(" "); + + cmd.add("delete"); + + if (tags != null) { + for(Tag tag : tags){ + cmd.add("t/" + tag); + } + } + + return cmd.toString(); + } + + /** Generates the correct delete command based on the slot. */ + String generateDeleteCommand(Slot slot) { + StringJoiner cmd = new StringJoiner(" "); + + cmd.add("delete"); + + Set tags = slot.getTags(); + if (tags != null) { + for(Tag tag : tags){ + cmd.add("t/" + tag); + } + } + + return cmd.toString(); + } + + // public String recurrenceToString(Recurrence recurrence) { + // StringJoiner cmd = new StringJoiner(" "); + // if (recurrence.recess) { + // cmd.add("r/" + "recess"); + // } + // if (reading) { + // cmd.add("r/" + "reading"); + // } + // if (normal) { + // cmd.add("r/" + "normal"); + // } + // if (exam) { + // cmd.add("r/" + "exam"); + // } + // if (past) { + // cmd.add("r/" + "past"); + // } + // return cmd.toString(); + // } /** * Generates an AddressBook with auto-generated persons. * @param isPrivateStatuses flags to indicate if all contact details of respective persons should be set to