diff --git a/doc/UserGuide.md b/doc/UserGuide.md index 3e4baae95..15276ba5a 100644 --- a/doc/UserGuide.md +++ b/doc/UserGuide.md @@ -50,6 +50,19 @@ Examples: * `find Betsy Tim John`
Returns Any person having names `Betsy`, `Tim`, or `John` +## Finding all persons containing any keyword in their tag: `find-tag` +Finds persons whose tags contain any of the given keywords.
+Format: `find-tag KEYWORD [MORE_KEYWORDS]` + +> The search is case sensitive, the order of the keywords does not matter, only the tag is searched, +and persons matching at least one keyword will be returned (i.e. `OR` search). + +Examples: +* `find-tag friend`
+ Returns `friend` but not `Friend` +* `find-tag friend CCA`
+ Returns Any person having tags `friend` or `CCA` + ## Deleting a person : `delete` Deletes the specified person from the address book. Irreversible.
Format: `delete INDEX` diff --git a/src/seedu/addressbook/commands/EditCommand.java b/src/seedu/addressbook/commands/EditCommand.java new file mode 100644 index 000000000..aa7623f87 --- /dev/null +++ b/src/seedu/addressbook/commands/EditCommand.java @@ -0,0 +1,70 @@ +package seedu.addressbook.commands; + +import java.util.HashSet; +import java.util.Set; + +import seedu.addressbook.common.Messages; +import seedu.addressbook.data.exception.IllegalValueException; +import seedu.addressbook.data.person.Address; +import seedu.addressbook.data.person.Email; +import seedu.addressbook.data.person.Name; +import seedu.addressbook.data.person.Person; +import seedu.addressbook.data.person.Phone; +import seedu.addressbook.data.person.ReadOnlyPerson; +import seedu.addressbook.data.person.UniquePersonList; +import seedu.addressbook.data.person.UniquePersonList.PersonNotFoundException; +import seedu.addressbook.data.tag.Tag; +import seedu.addressbook.data.tag.UniqueTagList; + +public class EditCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + "Edit a person in the address book. " + + "Contact details can be marked private by prepending 'p' to the prefix.\n\t" + + "Parameters: NAME [p]p/PHONE [p]e/EMAIL [p]a/ADDRESS [t/TAG]...\n\t" + + "Example: " + COMMAND_WORD + + " John Doe p/98765432 e/johnd@gmail.com a/311, Clementi Ave 2, #02-25 t/friends t/owesMoney"; + + public static final String MESSAGE_SUCCESS = "This person has been edited: %1$s"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; + + private final Person toEdit; + + public EditCommand(String name, + String phone, boolean isPhonePrivate, + String email, boolean isEmailPrivate, + String address, boolean isAddressPrivate, + Set tags) throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toEdit= new Person( + new Name(name), + new Phone(phone, isPhonePrivate), + new Email(email, isEmailPrivate), + new Address(address, isAddressPrivate), + new UniqueTagList(tagSet) + ); + } + + @Override + public CommandResult execute() { + try { + addressBook.addPerson(toEdit); + ReadOnlyPerson toRemove = null; + for (ReadOnlyPerson person : addressBook.getAllPersons()) { + if(person.getName().equals(toEdit.getName())) + toRemove = person; + } + addressBook.removePerson(toRemove); + return new CommandResult(String.format(MESSAGE_SUCCESS, toEdit)); + } catch (UniquePersonList.DuplicatePersonException dpe) { + return new CommandResult(MESSAGE_DUPLICATE_PERSON); + } catch (PersonNotFoundException pnfe) { + return new CommandResult(Messages.MESSAGE_PERSON_NOT_IN_ADDRESSBOOK); + } + } + +} diff --git a/src/seedu/addressbook/commands/FindTagCommand.java b/src/seedu/addressbook/commands/FindTagCommand.java new file mode 100644 index 000000000..b8ebd4cac --- /dev/null +++ b/src/seedu/addressbook/commands/FindTagCommand.java @@ -0,0 +1,69 @@ +package seedu.addressbook.commands; + +import seedu.addressbook.data.exception.IllegalValueException; +import seedu.addressbook.data.person.ReadOnlyPerson; +import seedu.addressbook.data.tag.Tag; +import seedu.addressbook.data.tag.UniqueTagList; + +import java.util.*; + +/** + * Finds and lists all persons in address book whose tags contains some of the argument keywords. + * Keyword matching is case sensitive. + */ +public class FindTagCommand extends Command{ + + public static final String COMMAND_WORD = "find-tag"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + "Finds all persons whose tags contain some of " + + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n\t" + + "Parameters: KEYWORD [MORE_KEYWORDS]...\n\t" + + "Example: " + COMMAND_WORD + " friend CCA"; + + private final Set keywords; + + public FindTagCommand(Set keywords) { + this.keywords = keywords; + } + + /** + * Returns copy of keywords in this command. + */ + public Set getKeywords() { + return new HashSet<>(keywords); + } + + @Override + public CommandResult execute() { + List personsFound; + try { + personsFound = getPersonsWithTagContainingAllKeyword(keywords); + } catch (IllegalValueException e) { + return new IncorrectCommand(e.getMessage()).execute(); + } + return new CommandResult(getMessageForPersonListShownSummary(personsFound), personsFound); + } + + /** + * Retrieve all persons in the address book whose tags contain some of the specified keywords. + * + * @param keywords for searching + * @return list of persons found + * @throws IllegalValueException + */ + private List getPersonsWithTagContainingAllKeyword(Set keywords) throws IllegalValueException { + final List matchedPersons = new ArrayList<>(); + for (ReadOnlyPerson person : addressBook.getAllPersons()) { + final UniqueTagList tags = person.getTags(); + for (String k : keywords) { + Tag tag = new Tag(k); + if (tags.contains(tag)) { + matchedPersons.add(person); + break; + } + } + } + return matchedPersons; + } + +} diff --git a/src/seedu/addressbook/commands/HelpCommand.java b/src/seedu/addressbook/commands/HelpCommand.java index 82530440c..779997cdd 100644 --- a/src/seedu/addressbook/commands/HelpCommand.java +++ b/src/seedu/addressbook/commands/HelpCommand.java @@ -14,7 +14,9 @@ public class HelpCommand extends Command { public static final String MESSAGE_ALL_USAGES = AddCommand.MESSAGE_USAGE + "\n" + DeleteCommand.MESSAGE_USAGE + "\n" + ClearCommand.MESSAGE_USAGE + + "\n" + EditCommand.MESSAGE_USAGE + "\n" + FindCommand.MESSAGE_USAGE + + "\n" + FindTagCommand.MESSAGE_USAGE + "\n" + ListCommand.MESSAGE_USAGE + "\n" + ViewCommand.MESSAGE_USAGE + "\n" + ViewAllCommand.MESSAGE_USAGE diff --git a/src/seedu/addressbook/commands/RemoveTag.java b/src/seedu/addressbook/commands/RemoveTag.java new file mode 100644 index 000000000..3db512680 --- /dev/null +++ b/src/seedu/addressbook/commands/RemoveTag.java @@ -0,0 +1,48 @@ +package seedu.addressbook.commands; + +import seedu.addressbook.data.exception.IllegalValueException; +import seedu.addressbook.data.person.ReadOnlyPerson; +import seedu.addressbook.data.tag.Tag; +import seedu.addressbook.data.tag.UniqueTagList; +import seedu.addressbook.data.tag.UniqueTagList.TagNotFoundException; + +public class RemoveTag extends Command{ + public static final String COMMAND_WORD="removetag"; + public static final String MESSAGE_USAGE=COMMAND_WORD+":\n"+ + "remove the tag from the address book. "+"Example: "+COMMAND_WORD+ + "frends"; + public static final String MESSAGE_SUCCESS="Tag deleted. "; + private final Tag toDelete; + public RemoveTag(String tagToDelete) throws IllegalValueException{ + toDelete=new Tag(tagToDelete); + } + public CommandResult execute(){ + removePersonWithTag(); + removeTagFromList(); + return new CommandResult(MESSAGE_SUCCESS); + } + private boolean removePersonWithTag(){ + boolean hasDeleted=false; + for(ReadOnlyPerson person: addressBook.getAllPersons()){ + final UniqueTagList tags=person.getTags(); + if(tags.contains(toDelete)){ + try { + tags.remove(toDelete); + } catch (TagNotFoundException e) { + e.printStackTrace(); + } + hasDeleted=true; + } + } + return hasDeleted; + } + private boolean removeTagFromList(){ + try { + addressBook.removeTag(toDelete); + } catch (TagNotFoundException e) { + return false; + } + return true; + } + +} diff --git a/src/seedu/addressbook/parser/Parser.java b/src/seedu/addressbook/parser/Parser.java index 3a8305f28..52c9c7bfe 100644 --- a/src/seedu/addressbook/parser/Parser.java +++ b/src/seedu/addressbook/parser/Parser.java @@ -48,8 +48,9 @@ public Parser() {} * * @param userInput full user input string * @return the command based on the user input + * @throws IllegalValueException */ - public Command parseCommand(String userInput) { + public Command parseCommand(String userInput) { final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); if (!matcher.matches()) { return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); @@ -68,8 +69,14 @@ public Command parseCommand(String userInput) { case ClearCommand.COMMAND_WORD: return new ClearCommand(); + case EditCommand.COMMAND_WORD: + return prepareEdit(arguments); + case FindCommand.COMMAND_WORD: return prepareFind(arguments); + + case FindTagCommand.COMMAND_WORD: + return prepareFindTag(arguments); case ListCommand.COMMAND_WORD: return new ListCommand(); @@ -79,6 +86,9 @@ public Command parseCommand(String userInput) { case ViewAllCommand.COMMAND_WORD: return prepareViewAll(arguments); + + case RemoveTag.COMMAND_WORD: + return prepareDeleteTag(arguments); case ExitCommand.COMMAND_WORD: return new ExitCommand(); @@ -88,6 +98,16 @@ public Command parseCommand(String userInput) { return new HelpCommand(); } } + private Command prepareDeleteTag(String args){ + Command deleteTag; + try { + deleteTag=new RemoveTag(args); + return deleteTag; + } catch (IllegalValueException e) { + return new IncorrectCommand(e.getMessage()); + } + + } /** * Parses arguments in the context of the add person command. @@ -227,6 +247,56 @@ private Command prepareFind(String args) { final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); return new FindCommand(keywordSet); } + + /** + * Parses arguments in the context of the find tag command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareFindTag(String args) { + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + // keywords delimited by whitespace + final String[] keywords = matcher.group("keywords").split("\\s+"); + final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); + return new FindTagCommand(keywordSet); + } + + + /** + * Parses arguments in the context of the add person command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareEdit(String args){ + final Matcher matcher = PERSON_DATA_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + try { + return new EditCommand( + matcher.group("name"), + + matcher.group("phone"), + isPrivatePrefixPresent(matcher.group("isPhonePrivate")), + matcher.group("email"), + isPrivatePrefixPresent(matcher.group("isEmailPrivate")), + + matcher.group("address"), + isPrivatePrefixPresent(matcher.group("isAddressPrivate")), + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } } \ No newline at end of file diff --git a/test/java/seedu/addressbook/parser/ParserTest.java b/test/java/seedu/addressbook/parser/ParserTest.java index f01be613c..cd9ab7eb1 100644 --- a/test/java/seedu/addressbook/parser/ParserTest.java +++ b/test/java/seedu/addressbook/parser/ParserTest.java @@ -292,6 +292,7 @@ private void parseAndAssertIncorrectWithMessage(String feedbackMessage, String.. * @param input to be parsed * @param expectedCommandClass expected class of returned command * @return the parsed command object + * */ private T parseAndAssertCommandType(String input, Class expectedCommandClass) { final Command result = parser.parseCommand(input);