diff --git a/src/main/java/seedu/waddle/logic/commands/EditItemCommand.java b/src/main/java/seedu/waddle/logic/commands/EditItemCommand.java index 729e081e1fb..9d01bf4ebbf 100644 --- a/src/main/java/seedu/waddle/logic/commands/EditItemCommand.java +++ b/src/main/java/seedu/waddle/logic/commands/EditItemCommand.java @@ -33,7 +33,7 @@ public class EditItemCommand extends Command { public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the item identified " + "by the index number used in the displayed item list. " + "Existing values will be overwritten by the input values.\n" - + "Parameters: " + + "Parameters: INDEX (must be a positive integer) " + "[" + PREFIX_DESCRIPTION + "DESCRIPTION]" + "[" + PREFIX_PRIORITY + "PRIORITY]" + "[" + PREFIX_COST + "COST]" diff --git a/src/main/java/seedu/waddle/logic/commands/PlanCommand.java b/src/main/java/seedu/waddle/logic/commands/PlanCommand.java new file mode 100644 index 00000000000..baea5f3a125 --- /dev/null +++ b/src/main/java/seedu/waddle/logic/commands/PlanCommand.java @@ -0,0 +1,79 @@ +package seedu.waddle.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.waddle.logic.parser.CliSyntax.PREFIX_DAY_NUMBER; +import static seedu.waddle.logic.parser.CliSyntax.PREFIX_START_TIME; + +import java.time.LocalTime; + +import seedu.waddle.commons.core.index.Index; +import seedu.waddle.logic.StageManager; +import seedu.waddle.logic.commands.exceptions.CommandException; +import seedu.waddle.model.Model; +import seedu.waddle.model.item.Item; +import seedu.waddle.model.itinerary.DayNumber; +import seedu.waddle.model.itinerary.Itinerary; + +/** + * Plans an item in the itinerary wish list. + */ +public class PlanCommand extends Command { + + public static final String COMMAND_WORD = "plan"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Schedules an item identified " + + "by the index number used in the item list.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_DAY_NUMBER + "DAY NUMBER] " + + "[" + PREFIX_START_TIME + "START TIME] " + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_DAY_NUMBER + "1 " + + PREFIX_START_TIME + "12:00 "; + + public static final String MESSAGE_SUCCESS = "Item scheduled: %1$s"; + public static final String MESSAGE_INVALID_DAY_NUMBER = "The day you have selected does not exist"; + + private final Index itemIndex; + private final DayNumber dayNumber; + private final LocalTime startTime; + + /** + * Creates an AddItemCommand to add the specified {@code Item} + */ + public PlanCommand(Index itemIndex, DayNumber dayNumber, LocalTime startTime) { + requireNonNull(itemIndex); + requireNonNull(dayNumber); + requireNonNull(startTime); + + this.itemIndex = itemIndex; + this.dayNumber = dayNumber; + this.startTime = startTime; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + StageManager stageManager = StageManager.getInstance(); + + Itinerary itinerary = stageManager.getSelectedItinerary(); + + Item plannedItem; + try { + plannedItem = itinerary.planItem(itemIndex, dayNumber, startTime); + } catch (IndexOutOfBoundsException e) { + throw new CommandException(MESSAGE_INVALID_DAY_NUMBER); + } + + return new CommandResult(String.format(MESSAGE_SUCCESS, plannedItem.getDescription())); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof PlanCommand // instanceof handles nulls + && itemIndex.equals(((PlanCommand) other).itemIndex) + && dayNumber == ((PlanCommand) other).dayNumber + && startTime.equals(((PlanCommand) other).startTime)); + } +} diff --git a/src/main/java/seedu/waddle/logic/parser/CliSyntax.java b/src/main/java/seedu/waddle/logic/parser/CliSyntax.java index a3809276ae6..6b69138aa88 100644 --- a/src/main/java/seedu/waddle/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/waddle/logic/parser/CliSyntax.java @@ -17,5 +17,6 @@ public class CliSyntax { public static final Prefix PREFIX_PRIORITY = new Prefix("p/"); public static final Prefix PREFIX_COST = new Prefix("c/"); public static final Prefix PREFIX_DURATION = new Prefix("du/"); + public static final Prefix PREFIX_DAY_NUMBER = new Prefix("d/"); } diff --git a/src/main/java/seedu/waddle/logic/parser/ParserUtil.java b/src/main/java/seedu/waddle/logic/parser/ParserUtil.java index ff1112d00d7..3ac0f42c443 100644 --- a/src/main/java/seedu/waddle/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/waddle/logic/parser/ParserUtil.java @@ -15,6 +15,7 @@ import seedu.waddle.model.itinerary.Budget; import seedu.waddle.model.itinerary.Country; import seedu.waddle.model.itinerary.Date; +import seedu.waddle.model.itinerary.DayNumber; import seedu.waddle.model.itinerary.ItineraryDuration; import seedu.waddle.model.itinerary.Name; import seedu.waddle.model.itinerary.People; @@ -195,6 +196,19 @@ public static Cost parseCost(String cost) throws ParseException { return new Cost(trimmedCost); } + /** + * Parses a {@code int Day Number}. + * Leading and trailing whitespaces will be trimmed. + */ + public static DayNumber parseDayNumber(String dayNumber) throws ParseException { + requireNonNull(dayNumber); + String trimmedDayNumber = dayNumber.trim(); + if (!DayNumber.isValidDayNumber(trimmedDayNumber)) { + throw new ParseException(DayNumber.MESSAGE_CONSTRAINTS); + } + return new DayNumber(trimmedDayNumber); + } + /** * Parses a {@code String duration} into a {@code Duration}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/waddle/logic/parser/PlanCommandParser.java b/src/main/java/seedu/waddle/logic/parser/PlanCommandParser.java index 38a0b6bb55d..02bd63524c4 100644 --- a/src/main/java/seedu/waddle/logic/parser/PlanCommandParser.java +++ b/src/main/java/seedu/waddle/logic/parser/PlanCommandParser.java @@ -2,37 +2,55 @@ import static java.util.Objects.requireNonNull; import static seedu.waddle.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.waddle.logic.parser.CliSyntax.PREFIX_DAY_NUMBER; +import static seedu.waddle.logic.parser.CliSyntax.PREFIX_START_TIME; + +import java.time.LocalTime; +import java.util.stream.Stream; import seedu.waddle.commons.core.index.Index; -import seedu.waddle.commons.exceptions.IllegalValueException; -import seedu.waddle.logic.commands.SelectCommand; +import seedu.waddle.logic.commands.PlanCommand; import seedu.waddle.logic.parser.exceptions.ParseException; +import seedu.waddle.model.itinerary.DayNumber; /** - * Parses input arguments and creates a new FindCommand object + * Parses input arguments and creates a new PlanCommand object */ public class PlanCommandParser { + /** * Parses the given {@code String} of arguments in the context of the PlanCommand * and returns a PlanCommand object for execution. - * - * @param args Arguments. - * @return PlanCommand. - * @throws ParseException If the user input does not conform the expected format. + * @throws ParseException if the user input does not conform to the expected format */ - public SelectCommand parse(String args) throws ParseException { + public PlanCommand parse(String args) throws ParseException { requireNonNull(args); - ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args); + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_DAY_NUMBER, PREFIX_START_TIME); + + if (!arePrefixesPresent(argMultimap, PREFIX_DAY_NUMBER, PREFIX_START_TIME)) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + PlanCommand.MESSAGE_USAGE)); + } Index index; try { index = ParserUtil.parseIndex(argMultimap.getPreamble()); - } catch (IllegalValueException ive) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, - SelectCommand.MESSAGE_USAGE), ive); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, PlanCommand.MESSAGE_USAGE), pe); } - return new SelectCommand(index); + DayNumber dayNumber = ParserUtil.parseDayNumber(argMultimap.getValue(PREFIX_DAY_NUMBER).get()); + LocalTime startTime = ParserUtil.parseStartTime(argMultimap.getValue(PREFIX_START_TIME).get()); + + return new PlanCommand(index, dayNumber, startTime); } -} + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/waddle/logic/parser/SelectCommandParser.java b/src/main/java/seedu/waddle/logic/parser/SelectCommandParser.java new file mode 100644 index 00000000000..c538c3a6db8 --- /dev/null +++ b/src/main/java/seedu/waddle/logic/parser/SelectCommandParser.java @@ -0,0 +1,38 @@ +package seedu.waddle.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.waddle.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.waddle.commons.core.index.Index; +import seedu.waddle.commons.exceptions.IllegalValueException; +import seedu.waddle.logic.commands.SelectCommand; +import seedu.waddle.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new SelectCommand object + */ +public class SelectCommandParser { + /** + * Parses the given {@code String} of arguments in the context of the SelectCommand + * and returns a SelectCommand object for execution. + * + * @param args Arguments + * @return SelectCommand + * @throws ParseException If the user input does not conform to the expected format + */ + public SelectCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args); + + Index index; + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (IllegalValueException ive) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + SelectCommand.MESSAGE_USAGE), ive); + } + + return new SelectCommand(index); + } +} + diff --git a/src/main/java/seedu/waddle/logic/parser/WaddleParser.java b/src/main/java/seedu/waddle/logic/parser/WaddleParser.java index ba53530339e..4e9529fe096 100644 --- a/src/main/java/seedu/waddle/logic/parser/WaddleParser.java +++ b/src/main/java/seedu/waddle/logic/parser/WaddleParser.java @@ -22,6 +22,7 @@ import seedu.waddle.logic.commands.HelpCommand; import seedu.waddle.logic.commands.HomeCommand; import seedu.waddle.logic.commands.ListCommand; +import seedu.waddle.logic.commands.PlanCommand; import seedu.waddle.logic.commands.SelectCommand; import seedu.waddle.logic.commands.StageCommand; import seedu.waddle.logic.parser.exceptions.ParseException; @@ -96,7 +97,7 @@ public Command parseHomeCommand(String commandWord, String arguments) throws Par return new ListCommand(); case SelectCommand.COMMAND_WORD: - return new PlanCommandParser().parse(arguments); + return new SelectCommandParser().parse(arguments); case HomeCommand.COMMAND_WORD: return new HomeCommand(); @@ -143,6 +144,9 @@ public Command parseWishCommand(String commandWord, String arguments) throws Par case DeleteItemCommand.COMMAND_WORD: return new DeleteItemCommandParser().parse(arguments); + case PlanCommand.COMMAND_WORD: + return new PlanCommandParser().parse(arguments); + //TODO: help commands must change here case HelpCommand.COMMAND_WORD: return new HelpCommand(); diff --git a/src/main/java/seedu/waddle/model/item/Cost.java b/src/main/java/seedu/waddle/model/item/Cost.java index 0ab70a80b19..cb9d218be47 100644 --- a/src/main/java/seedu/waddle/model/item/Cost.java +++ b/src/main/java/seedu/waddle/model/item/Cost.java @@ -19,7 +19,7 @@ public class Cost { public Cost(String cost) { requireNonNull(cost); checkArgument(isValidCost(cost), MESSAGE_CONSTRAINTS); - this.cost = Float.valueOf(cost); + this.cost = Float.parseFloat(cost); } /** @@ -28,7 +28,7 @@ public Cost(String cost) { public static boolean isValidCost(String test) { float value; try { - value = Float.valueOf(test); + value = Float.parseFloat(test); } catch (NumberFormatException e) { return false; } diff --git a/src/main/java/seedu/waddle/model/itinerary/DayNumber.java b/src/main/java/seedu/waddle/model/itinerary/DayNumber.java new file mode 100644 index 00000000000..0bce147d61c --- /dev/null +++ b/src/main/java/seedu/waddle/model/itinerary/DayNumber.java @@ -0,0 +1,47 @@ +package seedu.waddle.model.itinerary; + +import static java.util.Objects.requireNonNull; +import static seedu.waddle.commons.util.AppUtil.checkArgument; + +/** + * Represents an Itinerary's day number element. + * Guarantees: immutable; is valid as declared in {@link #isValidDayNumber(String)} + */ +public class DayNumber { + public static final String MESSAGE_CONSTRAINTS = + "Day number should only contain positive numbers"; + public static final String VALIDATION_REGEX = "\\d+"; + + public final int dayNumber; + + /** + * Constructs a {@code DayNumber}. + * + * @param dayNumber A valid value. + */ + public DayNumber(String dayNumber) { + requireNonNull(dayNumber); + checkArgument(isValidDayNumber(dayNumber), MESSAGE_CONSTRAINTS); + this.dayNumber = Integer.parseInt(dayNumber); + } + + /** + * Returns true if a given string is a valid day number. + */ + public static boolean isValidDayNumber(String test) { + return test.matches(VALIDATION_REGEX); + } + + + @Override + public String toString() { + return String.valueOf(dayNumber); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof seedu.waddle.model.itinerary.DayNumber // instanceof handles nulls + && dayNumber == ((seedu.waddle.model.itinerary.DayNumber) other).dayNumber); // state check + } +} diff --git a/src/main/java/seedu/waddle/model/itinerary/Itinerary.java b/src/main/java/seedu/waddle/model/itinerary/Itinerary.java index 44ab7e7dae7..a56cdf8f082 100644 --- a/src/main/java/seedu/waddle/model/itinerary/Itinerary.java +++ b/src/main/java/seedu/waddle/model/itinerary/Itinerary.java @@ -2,6 +2,7 @@ import static seedu.waddle.commons.util.CollectionUtil.requireAllNonNull; +import java.time.LocalTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -9,6 +10,7 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import seedu.waddle.commons.core.index.Index; import seedu.waddle.commons.core.index.MultiIndex; import seedu.waddle.logic.commands.exceptions.CommandException; import seedu.waddle.model.item.Day; @@ -182,16 +184,19 @@ public Item unplanItem(MultiIndex index) { /** * Plan an item. * @param itemIndex Index of item in unscheduled list. - * @param dayIndex Day to include this item. + * @param dayNumber Day to include this item. * @param startTime startTime of the item. + * @return The planned item. * @throws CommandException When adding item to specific day leads to conflict in time. */ - public void planItem(int itemIndex, int dayIndex, int startTime) throws CommandException { - Item item = this.unscheduledItemList.get(itemIndex); - Day day = this.days.get(dayIndex); + public Item planItem(Index itemIndex, DayNumber dayNumber, LocalTime startTime) throws CommandException { + Item item = this.unscheduledItemList.get(itemIndex.getZeroBased()); + item.setStartTime(startTime); + Day day = this.days.get(dayNumber.dayNumber); day.addItem(item); - this.unscheduledItemList.remove(itemIndex); + this.unscheduledItemList.remove(itemIndex.getZeroBased()); this.budget.updateSpending(item.getCost().getValue()); + return item; } public Item getItem(MultiIndex index) { diff --git a/src/main/java/seedu/waddle/model/itinerary/People.java b/src/main/java/seedu/waddle/model/itinerary/People.java index ebc039331f5..c6e62ab3cfc 100644 --- a/src/main/java/seedu/waddle/model/itinerary/People.java +++ b/src/main/java/seedu/waddle/model/itinerary/People.java @@ -11,13 +11,13 @@ public class People { public static final String MESSAGE_CONSTRAINTS = - "Number of people should only contain numbers"; + "Number of people should only contain positive numbers"; public static final String VALIDATION_REGEX = "\\d+"; public final String numOfPeople; /** - * Constructs a {@code Name}. + * Constructs a {@code People}. * * @param numOfPeople A valid value. */ @@ -28,7 +28,7 @@ public People(String numOfPeople) { } /** - * Returns true if a given string is a valid name. + * Returns true if a given string is a valid number of people. */ public static boolean isValidPeople(String test) { return test.matches(VALIDATION_REGEX);