Skip to content

Commit

Permalink
Merge ec6afc7 into bb9047a
Browse files Browse the repository at this point in the history
  • Loading branch information
charrizard47 committed Apr 9, 2020
2 parents bb9047a + ec6afc7 commit 883e808
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 6 deletions.
46 changes: 46 additions & 0 deletions src/main/java/seedu/address/logic/commands/FilterCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_SPORT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
import seedu.address.model.client.TagAndSportContainsKeywordsPredicate;

/**
* @author tohkerwei
* Filters and lists all clients in FitBiz whose tag or sports contains argument keywords for the respective parameters.
* Keyword matching is case insensitive.
*/
public class FilterCommand extends Command {

public static final String COMMAND_WORD = "filter-c";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters and display all clients whose tags or sports "
+ "contains any of the specified keywords for respective parameter (case-insensitive) \n"
+ "Parameters: t/KEYWORD... s/KEYWORD...\n"
+ "Example: " + COMMAND_WORD + " " + PREFIX_TAG + "normal" + " " + PREFIX_SPORT + "hockey";

private final TagAndSportContainsKeywordsPredicate predicate;

public FilterCommand(TagAndSportContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredClientList(predicate);
return new CommandResult(
String.format(Messages.MESSAGE_CLIENTS_LISTED_OVERVIEW, model.getFilteredClientList().size()));
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof FilterCommand // instanceof handles nulls
&& predicate.equals(((FilterCommand) other).predicate)); // state check
}
}

89 changes: 89 additions & 0 deletions src/main/java/seedu/address/logic/parser/FilterCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_SPORT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.client.Sport;
import seedu.address.model.client.TagAndSportContainsKeywordsPredicate;
import seedu.address.model.tag.Tag;

/**
* Parses input arguments and creates a new FilterCommand object
*/
public class FilterCommandParser implements Parser<FilterCommand> {

/**
* @author tohkerwei
* 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 FilterCommand parse(String args) throws ParseException {

ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_TAG, PREFIX_SPORT);

boolean hasTag = argMultimap.getValue(PREFIX_TAG).isPresent();
boolean hasSport = argMultimap.getValue(PREFIX_SPORT).isPresent();

if (!hasTag && !hasSport) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}

List<String> tags = getTagsFromMap(argMultimap);
List<String> sports = getSportsFromMap(argMultimap);

return new FilterCommand(new TagAndSportContainsKeywordsPredicate(splitKeywords(tags), splitKeywords(sports)));
}

/**
* Splits the tags input by " "
* @param list List of tag input
* @return List of tags
*/
public List<String> splitKeywords(List<String> list) {
List<String> keywords = new ArrayList<>();
if (!list.isEmpty()) {
String[] keywordArray = list.get(0).split(" ");
keywords.addAll(Arrays.asList(keywordArray));
}
return keywords;
}

/**
* Returns a list of string of tags
* @param argMultimap map of input
* @return List of strings of tags
* @throws ParseException if there are no tags
*/
public List<String> getTagsFromMap(ArgumentMultimap argMultimap) throws ParseException {
Set<Tag> tagSet = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
List<String> tags = new ArrayList<String>();
for (Tag tag : tagSet) {
tags.add(tag.tagName);
}
return tags;
}

/**
* Returns a list of strings of sports
* @param argMultimap map of input
* @return List of strings of sports
* @throws ParseException if there are no sports
*/
public List<String> getSportsFromMap(ArgumentMultimap argMultimap) throws ParseException {
Set<Sport> sportSet = ParserUtil.parseSports(argMultimap.getAllValues(PREFIX_SPORT));
List<String> sports = new ArrayList<String>();
for (Sport sport : sportSet) {
sports.add(sport.sportName);
}
return sports;
}
}
4 changes: 4 additions & 0 deletions src/main/java/seedu/address/logic/parser/FitBizParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import seedu.address.logic.commands.EditExerciseCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.ExportCommand;
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
Expand Down Expand Up @@ -92,6 +93,9 @@ public Command parseCommand(String userInput) throws ParseException {
case ViewCommand.COMMAND_WORD:
return new ViewCommandParser().parse(arguments);

case FilterCommand.COMMAND_WORD:
return new FilterCommandParser().parse(arguments);

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package seedu.address.model.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import seedu.address.commons.util.StringUtil;
import seedu.address.model.tag.Tag;

/**
* @author tohkerwei
* Tests that a {@code Client}'s {@code Name} matches any of the keywords given.
*/
public class TagAndSportContainsKeywordsPredicate implements Predicate<Client> {

private final List<String> tagKeywords;
private final List<String> sportKeywords;

public TagAndSportContainsKeywordsPredicate(List<String> tagKeywords, List<String> sportKeywords) {

this.tagKeywords = tagKeywords;
this.sportKeywords = sportKeywords;
}

@Override
public boolean test(Client client) {
boolean hasTag;
boolean hasSport;
if (tagKeywords.isEmpty()) {
hasTag = true;
} else {
hasTag = tagKeywords.stream()
.allMatch(keyword -> StringUtil.containsWordIgnoreCase(setTagToString(client.getTags()), keyword));
}

if (sportKeywords.isEmpty()) {
hasSport = true;
} else {
hasSport = sportKeywords.stream()
.allMatch(keyword -> StringUtil
.containsWordIgnoreCase(setSportToString(client.getSports()), keyword));
}

return hasTag && hasSport;
}

/**
* Converts the tags of a client into a string
* @param tagsSet set of tags of a client
* @return string containing tags of a client
*/
public String setTagToString(Set<Tag> tagsSet) {
StringBuilder sb = new StringBuilder();
ArrayList<String> tagArray = new ArrayList<>();
for (Tag tag : tagsSet) {
tagArray.add(tag.tagName);
}
for (int i = 0; i < tagsSet.size(); i++) {
sb.append(tagArray.get(i));
sb.append(" ");
}
return sb.toString();
}

/**
* Converts the sports of a client into a string
* @param sportSet set of sports of a client
* @return string containing sports of a client
*/
public String setSportToString(Set<Sport> sportSet) {
StringBuilder sb = new StringBuilder();
ArrayList<String> sportArray = new ArrayList<>();
for (Sport sport : sportSet) {
sportArray.add(sport.sportName);
}
for (int i = 0; i < sportSet.size(); i++) {
sb.append(sportArray.get(i));
sb.append(" ");
}
return sb.toString();
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof TagAndSportContainsKeywordsPredicate // instanceof handles nulls
&& tagKeywords.equals(((TagAndSportContainsKeywordsPredicate) other).tagKeywords)
|| sportKeywords.equals(((TagAndSportContainsKeywordsPredicate) other).sportKeywords)); // state check
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"email" : "werner@example.com",
"address" : "michegan ave",
"birthday" : "",
"tagged" : [ ],
"tagged" : [],
"currentWeight" : "",
"targetWeight" : "",
"height" : "",
Expand All @@ -72,7 +72,7 @@
"email" : "lydia@example.com",
"address" : "little tokyo",
"birthday" : "",
"tagged" : [ ],
"tagged" : ["normal"],
"currentWeight" : "",
"targetWeight" : "",
"height" : "",
Expand All @@ -85,11 +85,11 @@
"email" : "anna@example.com",
"address" : "4th street",
"birthday" : "",
"tagged" : [ ],
"tagged" : ["normal"],
"currentWeight" : "",
"targetWeight" : "",
"height" : "",
"remark" : "",
"sports" : [ ]
"sports" : ["dance"]
} ]
}
106 changes: 106 additions & 0 deletions src/test/java/seedu/address/logic/commands/FilterCommandTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package seedu.address.logic.commands;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.commons.core.Messages.MESSAGE_CLIENTS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;

import static seedu.address.testutil.TypicalClients.getTypicalFitBiz;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

import seedu.address.model.ClientInView;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.client.TagAndSportContainsKeywordsPredicate;

/**
* Contains integration tests (interaction with the Model) for {@code FilterCommand}.
*/
public class FilterCommandTest {
private Model model = new ModelManager(getTypicalFitBiz(), new UserPrefs(), new ClientInView());
private Model expectedModel = new ModelManager(getTypicalFitBiz(), new UserPrefs(), new ClientInView());

@Test
public void equals() {
TagAndSportContainsKeywordsPredicate firstPredicate =
new TagAndSportContainsKeywordsPredicate(Collections.singletonList("firsttag"),
Collections.singletonList("firstsport"));
TagAndSportContainsKeywordsPredicate secondPredicate =
new TagAndSportContainsKeywordsPredicate(Collections.singletonList("secondtag"),
Collections.singletonList("secondsport"));

FilterCommand filterFirstCommand = new FilterCommand(firstPredicate);
FilterCommand filterSecondCommand = new FilterCommand(secondPredicate);

// same object -> returns true
assertTrue(filterFirstCommand.equals(filterFirstCommand));

// same values -> returns true
FilterCommand filterFirstCommandCopy = new FilterCommand(firstPredicate);
assertTrue(filterFirstCommand.equals(filterFirstCommandCopy));

// different types -> returns false
assertFalse(filterFirstCommand.equals(1));

// null -> returns false
assertFalse(filterFirstCommand.equals(null));

// different client -> returns false
assertFalse(filterFirstCommand.equals(filterSecondCommand));
}

@Test
public void execute_validTagAndSport_clientFound() {
String expectedMessage = String.format(MESSAGE_CLIENTS_LISTED_OVERVIEW, 1);
TagAndSportContainsKeywordsPredicate predicate = preparePredicate("normal",
"dance");
FilterCommand command = new FilterCommand(predicate);
expectedModel.updateFilteredClientList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
}

@Test
public void execute_validTagNoSport_multipleClientsFound() {
String expectedMessage = String.format(MESSAGE_CLIENTS_LISTED_OVERVIEW, 2);
TagAndSportContainsKeywordsPredicate predicate = preparePredicate("normal",
"");
FilterCommand command = new FilterCommand(predicate);
expectedModel.updateFilteredClientList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
}

@Test
public void execute_validSportNoTag_multipleClientsFound() {
String expectedMessage = String.format(MESSAGE_CLIENTS_LISTED_OVERVIEW, 1);
TagAndSportContainsKeywordsPredicate predicate = preparePredicate("",
"dance");
FilterCommand command = new FilterCommand(predicate);
expectedModel.updateFilteredClientList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
}

/**
* Parses {@code tagInput and @code sportInput} into a {@code TagAndSportContainsKeywordsPredicate}.
*/
private TagAndSportContainsKeywordsPredicate preparePredicate(String tagInput, String sportInput) {
List<String> tags = new ArrayList<>();
List<String> sports = new ArrayList<>();
if (!tagInput.equals("")) {
tags = Arrays.asList(tagInput.split("\\s+"));
}

if (!sportInput.equals("")) {
sports = Arrays.asList(sportInput.split("\\s+"));
}
return new TagAndSportContainsKeywordsPredicate(tags, sports);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class CommandParserTestUtil {
public static void assertParseSuccess(Parser parser, String userInput, Command expectedCommand) {
try {
Command command = parser.parse(userInput);
System.out.println(command);
System.out.println(expectedCommand);
assertEquals(expectedCommand, command);
} catch (ParseException pe) {
throw new IllegalArgumentException("Invalid userInput.", pe);
Expand Down
Loading

0 comments on commit 883e808

Please sign in to comment.