Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2324S1#108 from Chrainx/Match-Feature
Browse files Browse the repository at this point in the history
add Match feature
  • Loading branch information
Chrainx authored Oct 30, 2023
2 parents b74d88b + 3b3b7e2 commit 8fe5eeb
Show file tree
Hide file tree
Showing 21 changed files with 746 additions and 17 deletions.
5 changes: 5 additions & 0 deletions src/main/java/seedu/address/logic/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public class Messages {
public static final String MESSAGE_INVALID_CUSTOMER_DISPLAYED_INDEX = "The customer index provided is invalid";

public static final String MESSAGE_INVALID_PROPERTY_DISPLAYED_INDEX = "The property index provided is invalid";

public static final String MESSAGE_CUSTOMERS_MATCH_OVERVIEW = "%1$d properties matched with customer ";

public static final String MESSAGE_PROPERTIES_MATCH_OVERVIEW = "%1$d customers matched with property ";
public static final String MESSAGE_CUSTOMERS_LISTED_OVERVIEW = "%1$d customers listed!";
public static final String MESSAGE_PROPERTIES_LISTED_OVERVIEW = "%1$d properties listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Set;

import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.customer.Budget;
import seedu.address.model.customer.Customer;
import seedu.address.model.property.Price;
import seedu.address.model.property.PriceAndTagsInRangePredicate;
import seedu.address.model.tag.Tag;

/**
* Match all properties in the property book to the user based on specific tags
* and/or budget satisfy the customer criteria.
*/
public class MatchCustomerCommand extends Command {
public static final String COMMAND_WORD = "matchcust";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Match customers from the address book. \n"
+ "Parameters: "
+ "Index" + "\n"
+ "Example: " + COMMAND_WORD + " 2";

public static final String MESSAGE_FAIL = "There is no customer with index ";
private Index targetIndex;

/**
* Creates a MatchCustomerCommand to get all the specified {@code Property}
*/
public MatchCustomerCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Customer> lastShownList = model.getFilteredCustomerList();

try {
Customer targetCustomer = lastShownList.get(targetIndex.getZeroBased());
Budget budget = targetCustomer.getBudget();
Set<Tag> tags = targetCustomer.getTags();

Price maxPrice = budget.convertToPrice();
PriceAndTagsInRangePredicate predicate = new PriceAndTagsInRangePredicate(maxPrice, tags);

model.updateMatchedCustomerList(targetCustomer, predicate);

return new CommandResult(
String.format(
Messages.MESSAGE_CUSTOMERS_MATCH_OVERVIEW + targetIndex.getOneBased(),
model.getFilteredPropertyList().size()
)
);
} catch (IndexOutOfBoundsException e) {
throw new CommandException(MESSAGE_FAIL + targetIndex.getOneBased());
}
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof MatchCustomerCommand)) {
return false;
}

MatchCustomerCommand otherMatchCustomerCommand = (MatchCustomerCommand) other;
return targetIndex.equals(otherMatchCustomerCommand.targetIndex);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("Index", targetIndex)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Set;

import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.customer.Budget;
import seedu.address.model.customer.BudgetAndTagsInRangePredicate;
import seedu.address.model.property.Price;
import seedu.address.model.property.Property;
import seedu.address.model.tag.Tag;

/**
* Match all properties in the property book to the user based on specific tags
* and/or budget satisfy the customer criteria.
*/
public class MatchPropertyCommand extends Command {
public static final String COMMAND_WORD = "matchprop";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Match properties from the property book. \n"
+ "Parameters: "
+ "Index" + "\n"
+ "Example: " + COMMAND_WORD + " 2";

public static final String MESSAGE_FAIL = "There is no property with index ";
private Index targetIndex;

/**
* Creates a MatchPropertyCommand to get all the specified {@code Customer}
*/
public MatchPropertyCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Property> lastShownList = model.getFilteredPropertyList();

try {
Property targetProperty = lastShownList.get(targetIndex.getZeroBased());

Price price = targetProperty.getPrice();
Set<Tag> tags = targetProperty.getTags();

Budget minBudget = price.convertToBudget();
BudgetAndTagsInRangePredicate predicate = new BudgetAndTagsInRangePredicate(minBudget, tags);

model.updateMatchedPropertyList(targetProperty, predicate);

return new CommandResult(
String.format(
Messages.MESSAGE_PROPERTIES_MATCH_OVERVIEW + targetIndex.getOneBased(),
model.getFilteredCustomerList().size()
)
);
} catch (IndexOutOfBoundsException e) {
throw new CommandException(MESSAGE_FAIL + targetIndex.getOneBased());
}
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof MatchPropertyCommand)) {
return false;
}

MatchPropertyCommand otherMatchPropertyCommand = (MatchPropertyCommand) other;
return targetIndex.equals(otherMatchPropertyCommand.targetIndex);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("Index", targetIndex)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCustomerCommand;
import seedu.address.logic.commands.ListPropertyCommand;
import seedu.address.logic.commands.MatchCustomerCommand;
import seedu.address.logic.commands.MatchPropertyCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand Down Expand Up @@ -91,6 +93,12 @@ public Command parseCommand(String userInput) throws ParseException {
case ListPropertyCommand.COMMAND_WORD:
return new ListPropertyCommand();

case MatchCustomerCommand.COMMAND_WORD:
return new MatchCustomerCommandParser().parse(arguments);

case MatchPropertyCommand.COMMAND_WORD:
return new MatchPropertyCommandParser().parse(arguments);

case ExitCommand.COMMAND_WORD:
return new ExitCommand();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package seedu.address.logic.parser;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.MatchCustomerCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
* Filters and lists all customers in address book whose budget and/or tags are selected.
*/
public class MatchCustomerCommandParser implements Parser<MatchCustomerCommand> {

/**
* Parses the given {@code String} of arguments in the context of the FilterCommand
* and returns a FilterCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public MatchCustomerCommand parse(String args) throws ParseException {
requireNonNull(args);
Index index;

try {
index = ParserUtil.parseIndex(args);
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT,
MatchCustomerCommand.MESSAGE_USAGE),
pe
);
}

return new MatchCustomerCommand(index);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package seedu.address.logic.parser;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.MatchPropertyCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
* Match and lists all customers in address book whose budget and/or tags satisfy with the property.
*/
public class MatchPropertyCommandParser implements Parser<MatchPropertyCommand> {

/**
* Parses the given {@code String} of arguments in the context of the MatchPropertyCommand
* and returns a MatchPropertyCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public MatchPropertyCommand parse(String args) throws ParseException {
requireNonNull(args);
Index index;

try {
index = ParserUtil.parseIndex(args);
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT,
MatchPropertyCommand.MESSAGE_USAGE),
pe
);
}

return new MatchPropertyCommand(index);
}

}
12 changes: 12 additions & 0 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,16 @@ public interface Model {
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPropertyList(Predicate<Property> predicate);

/**
* Deletes the given customer.
* The customer must exist in the address book.
*/
void updateMatchedCustomerList(Customer targetCustomer, Predicate<Property> predicate);

/**
* Deletes the given property.
* The property must exist in the PropertyMatch.
*/
void updateMatchedPropertyList(Property targetProperty, Predicate<Customer> predicate);
}
17 changes: 17 additions & 0 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.customer.Customer;
import seedu.address.model.customer.SameCustomerPredicate;
import seedu.address.model.property.Property;
import seedu.address.model.property.SamePropertyPredicate;

/**
* Represents the in-memory model of the address book data.
Expand Down Expand Up @@ -183,6 +185,14 @@ public void updateFilteredCustomerList(Predicate<Customer> predicate) {
filteredCustomers.setPredicate(predicate);
}

@Override
public void updateMatchedCustomerList(Customer targetCustomer, Predicate<Property> predicate) {
requireAllNonNull(targetCustomer, predicate);
Predicate<Customer> custPredicate = new SameCustomerPredicate(targetCustomer);
filteredCustomers.setPredicate(custPredicate);
filteredProperties.setPredicate(predicate);
}

//=========== Filtered Property List Accessors =============================================================

/**
Expand All @@ -200,6 +210,13 @@ public void updateFilteredPropertyList(Predicate<Property> predicate) {
filteredProperties.setPredicate(predicate);
}

@Override
public void updateMatchedPropertyList(Property targetProperty, Predicate<Customer> predicate) {
requireAllNonNull(targetProperty, predicate);
Predicate<Property> propPredicate = new SamePropertyPredicate(targetProperty);
filteredProperties.setPredicate(propPredicate);
filteredCustomers.setPredicate(predicate);
}

@Override
public boolean equals(Object other) {
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/seedu/address/model/customer/Budget.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;

import seedu.address.model.property.Price;

/**
* Represents a Customer's budget in the address book.
* Guarantees: immutable; is valid as declared in {@link #isValidBudget(String)}
Expand Down Expand Up @@ -37,7 +39,7 @@ public static boolean isValidBudget(String test) {
}

/**
* Returns true if the other budget is greater or equal this budget
* Returns true if the other budget is greater or equal this budget.
*
* @param other the other budget being compared
* @return whether the other budget is greater or equal to this budget
Expand All @@ -46,6 +48,14 @@ public boolean isInRangeBudget(Budget other) {
return isNull(other) || amount >= other.amount;
}

/**
* Convert the budget to a price object.
*
* @return a Price object that have the same amount with the budget.
*/
public Price convertToPrice() {
return new Price(value);
}
@Override
public String toString() {
return "$" + value;
Expand Down
Loading

0 comments on commit 8fe5eeb

Please sign in to comment.