Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2122S1#64 from KT27Learn/branch-sortC…
Browse files Browse the repository at this point in the history
…ommand

Implement Sort Command
  • Loading branch information
wyrchris authored Oct 13, 2021
2 parents 2c7bcd8 + fee46d6 commit 2b37f26
Show file tree
Hide file tree
Showing 25 changed files with 878 additions and 48 deletions.
1 change: 1 addition & 0 deletions src/main/java/seedu/address/commons/core/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ public class Messages {
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_VIEW_SUCCESS = "Viewing person: %1$s";
public static final String MESSAGE_VIEW_INVALID_CLIENT_ID = "There's no contact with client ID %s";
public static final String MESSAGE_SORT_SUCCESS = "List sorted by %s";

}
2 changes: 2 additions & 0 deletions src/main/java/seedu/address/logic/commands/EditCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
setDisposableIncome(toCopy.disposableIncome);
setRiskAppetite(toCopy.riskAppetite);
setLastMet(toCopy.lastMet);
setCurrentPlan(toCopy.currentPlan);
setDisposableIncome(toCopy.disposableIncome);
Expand Down
30 changes: 21 additions & 9 deletions src/main/java/seedu/address/logic/commands/SortCommand.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.Comparator;

import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.Person;

/**
* Sorts all persons in address book whose according to the specified attribute in either ascending or descending
Expand All @@ -14,26 +19,33 @@ public class SortCommand extends Command {
public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sorts leads according to "
+ "the specified attribute and in either an ascending or descending order\n"
+ "Parameters: <attribute>/{ASC/DESC}\n"
+ "Example: " + COMMAND_WORD + " ra/ ASC";

+ "Example: " + COMMAND_WORD + " ra/ asc";

private final Comparator<Person> sorter;

public SortCommand() {
private final String field;

/**
* @param sorter to sort the persons list with.
* @param field which is the field that the list is sorted by.
*/
public SortCommand(Comparator<Person> sorter, String field) {
this.sorter = sorter;
this.field = field;
}

@Override
public CommandResult execute(Model model) {


return new CommandResult(
String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
requireNonNull(model);
model.sortFilteredPersonList(sorter);
return new CommandResult(String.format(Messages.MESSAGE_SORT_SUCCESS, field));
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| other instanceof SortCommand; // instanceof handles nulls
//&& predicate.equals(((SortCommand) other).predicate)); // state check
|| (other instanceof SortCommand // instanceof handles nulls
&& sorter.equals(((SortCommand) other).sorter)
&& field.equals(((SortCommand) other).field)); // state check
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.SearchCommand;
import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.commands.ViewCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
Expand Down Expand Up @@ -72,6 +73,9 @@ public Command parseCommand(String userInput) throws ParseException {
case SearchCommand.COMMAND_WORD:
return new SearchCommandParser().parse(arguments);

case SortCommand.COMMAND_WORD:
return new SortCommandParser().parse(arguments);

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

Expand Down
21 changes: 20 additions & 1 deletion src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import seedu.address.model.person.Name;
import seedu.address.model.person.Phone;
import seedu.address.model.person.RiskAppetite;
import seedu.address.model.person.comparators.SortDirection;
import seedu.address.model.tag.Tag;

/**
Expand Down Expand Up @@ -140,6 +141,9 @@ public static CurrentPlan parseCurrentPlan(String currentPlan) throws ParseExcep
public static LastMet parseLastMet(String lastMet) throws ParseException {
requireNonNull(lastMet);
String trimmedLastMet = lastMet.trim();
if (!LastMet.isValidLastMet(trimmedLastMet)) {
throw new ParseException(LastMet.MESSAGE_CONSTRAINTS);
}
return new LastMet(trimmedLastMet);
}

Expand All @@ -158,7 +162,7 @@ public static RiskAppetite parseRiskAppetite(String riskAppetite) throws ParseEx
}

/**
* Parses a {@code String disposableIncome} into an {@code disposableIncome}.
* Parses a {@code String disposableIncome} into an {@code DisposableIncome}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code DisposableIncome} is invalid.
Expand All @@ -172,6 +176,21 @@ public static DisposableIncome parseDisposableIncome(String disposableIncome) th
return new DisposableIncome(trimmedDisposableIncome);
}

/**
* Parses a {@code String sortDirection} into an {@code SortDirection}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code DisposableIncome} is invalid.
*/
public static SortDirection parseSortDirection(String sortDirection) throws ParseException {
requireNonNull(sortDirection);
String trimmedSortDirection = sortDirection.trim();
if (!SortDirection.isValidDirection(trimmedSortDirection)) {
throw new ParseException(SortDirection.MESSAGE_CONSTRAINTS);
}
return new SortDirection(trimmedSortDirection);
}

/**
* Parses a {@code String tag} into a {@code Tag}.
* Leading and trailing whitespaces will be trimmed.
Expand Down
110 changes: 108 additions & 2 deletions src/main/java/seedu/address/logic/parser/SortCommandParser.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.commons.core.Messages.MESSAGE_TOO_MANY_FIELDS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_CLIENTID;
import static seedu.address.logic.parser.CliSyntax.PREFIX_CURRENTPLAN;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DISPOSABLEINCOME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_LASTMET;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_RISKAPPETITE;
import static seedu.address.logic.parser.ParserUtil.parseSortDirection;

import java.util.Comparator;
import java.util.stream.Stream;

import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.SortCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Person;
import seedu.address.model.person.comparators.SortByAddress;
import seedu.address.model.person.comparators.SortByClientID;
import seedu.address.model.person.comparators.SortByCurrentPlan;
import seedu.address.model.person.comparators.SortByDisposableIncome;
import seedu.address.model.person.comparators.SortByEmail;
import seedu.address.model.person.comparators.SortByLastMet;
import seedu.address.model.person.comparators.SortByName;
import seedu.address.model.person.comparators.SortByPhone;
import seedu.address.model.person.comparators.SortByRiskAppetite;
import seedu.address.model.person.comparators.SortDirection;

public class SortCommandParser implements Parser<SortCommand> {

private static final Prefix[] ALL_PREFIXES = {
PREFIX_CLIENTID, PREFIX_NAME, PREFIX_EMAIL, PREFIX_PHONE, PREFIX_ADDRESS, PREFIX_RISKAPPETITE,
PREFIX_DISPOSABLEINCOME, PREFIX_CURRENTPLAN, PREFIX_LASTMET
};

private String sortedField;

/**
* Parses the given {@code String} of arguments in the context of the FindCommand
* and returns a SortCommand object for execution.
Expand All @@ -20,8 +52,82 @@ public SortCommand parse(String args) throws ParseException {
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

String[] nameKeywords = trimmedArgs.split("\\s+");
return new SortCommand();
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_CLIENTID, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
PREFIX_ADDRESS, PREFIX_RISKAPPETITE, PREFIX_DISPOSABLEINCOME, PREFIX_CURRENTPLAN, PREFIX_LASTMET);
if (!anyPrefixesPresent(argMultimap, PREFIX_CLIENTID, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
PREFIX_RISKAPPETITE, PREFIX_DISPOSABLEINCOME, PREFIX_CURRENTPLAN, PREFIX_LASTMET)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
}

Comparator<Person> sorter = parseSorter(argMultimap);

return new SortCommand(sorter, sortedField);
}

/**
* Returns true if any of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
*/
private static boolean anyPrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
return Stream.of(prefixes).anyMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}

/**
* Constructs a {@code Comparator} from based off inputted {@code Prefix} with given {@code SortDirection}
*/
private Comparator<Person> createSorter(Prefix prefix, SortDirection sortDirection) throws ParseException {
if (PREFIX_CLIENTID.equals(prefix)) {
sortedField = "Client Id";
return new SortByClientID(sortDirection);
} else if (PREFIX_NAME.equals(prefix)) {
sortedField = "Name";
return new SortByName(sortDirection);
} else if (PREFIX_EMAIL.equals(prefix)) {
sortedField = "Email";
return new SortByEmail(sortDirection);
} else if (PREFIX_PHONE.equals(prefix)) {
sortedField = "Phone";
return new SortByPhone(sortDirection);
} else if (PREFIX_ADDRESS.equals(prefix)) {
sortedField = "Address";
return new SortByAddress(sortDirection);
} else if (PREFIX_RISKAPPETITE.equals(prefix)) {
sortedField = "Risk Appetite";
return new SortByRiskAppetite(sortDirection);
} else if (PREFIX_DISPOSABLEINCOME.equals(prefix)) {
sortedField = "Disposable Income";
return new SortByDisposableIncome(sortDirection);
} else if (PREFIX_CURRENTPLAN.equals(prefix)) {
sortedField = "Current Plan";
return new SortByCurrentPlan(sortDirection);
} else if (PREFIX_LASTMET.equals(prefix)) {
sortedField = "Last Met";
return new SortByLastMet(sortDirection);
} else {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SortCommand.MESSAGE_USAGE));
}

}

/**
* Constructs a {@code Comparator} from parsed prefixes in {@code ArgumentMultiMap }based off inputted prefix
* with appriopriate {@code SortDirection}
*/
private Comparator<Person> parseSorter(ArgumentMultimap argumentMultimap) throws ParseException {
Comparator<Person> sorter = null;
for (int i = 0; i < ALL_PREFIXES.length; i++) {
Prefix currentPrefix = ALL_PREFIXES[i];
if (!argumentMultimap.getValue(currentPrefix).isEmpty() && sorter == null) {
SortDirection sortDirection = parseSortDirection(argumentMultimap.getValue(currentPrefix).get());
sorter = createSorter(currentPrefix, sortDirection);
} else if (!argumentMultimap.getValue(currentPrefix).isEmpty() && !(sorter == null)) {
//too many fields
throw new ParseException(String.format(MESSAGE_TOO_MANY_FIELDS, SortCommand.MESSAGE_USAGE));
}
}
return sorter;
}

}
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package seedu.address.model;

import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;

Expand Down Expand Up @@ -103,6 +104,12 @@ public interface Model {
*/
void filterFilteredPersonList(Predicate<Person> predicate);

/**
* Sorts the filtered person list to sort by the given {@code sorter}.
* @throws NullPointerException if {@code predicate} is null.
*/
void sortFilteredPersonList(Comparator<Person> sorter);

/** Returns an unmodifiable view of the person to view */
ObservableList<Person> getPersonToView();

Expand Down
11 changes: 10 additions & 1 deletion src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.logging.Logger;

import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.model.person.ClientId;
Expand All @@ -23,6 +25,7 @@ public class ModelManager implements Model {

private final AddressBook addressBook;
private final UserPrefs userPrefs;
private final SortedList<Person> sortedPersons;
private final FilteredList<Person> filteredPersons;
private final FilteredList<Person> personToView;

Expand All @@ -37,7 +40,8 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs

this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
sortedPersons = new SortedList<>(this.addressBook.getPersonList());
filteredPersons = new FilteredList<>(sortedPersons);
personToView = new FilteredList<>(this.addressBook.getPersonList());
}

Expand Down Expand Up @@ -154,6 +158,11 @@ public void filterFilteredPersonList(Predicate<Person> predicate) {
filteredPersons.setPredicate(predicate.and(currentPredicate));
}

@Override
public void sortFilteredPersonList(Comparator<Person> sorter) {
sortedPersons.setComparator(sorter);
}

//=========== Person To View List Accessors =============================================================

/**
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/seedu/address/model/person/RiskAppetite.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ public boolean equals(Object other) {
public int hashCode() {
return value.hashCode();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package seedu.address.model.person.comparators;

import static java.util.Objects.requireNonNull;

import java.util.Comparator;

import seedu.address.model.person.Person;

public class SortByAddress implements Comparator<Person> {
private SortDirection direction;

/**
* @param direction to sort by. Either asc or dsc.
*/
public SortByAddress(SortDirection direction) {
requireNonNull(direction);
this.direction = direction;
}

@Override
public int compare(Person a, Person b) {
//cause i need the sort direction here, i implement compareTo in riskAppetite
//cause if not i need double check here for empty values
//wrt person a
if (a.getAddress().value.isEmpty()) {
return 1;
} else {
if (b.getAddress().value.isEmpty()) {
return -1;
}

int result = a.getAddress().value.compareTo(b.getAddress().value);
return direction.isAscending() ? result : -result;
}
}
}
Loading

0 comments on commit 2b37f26

Please sign in to comment.