package net.thirdy.blackmarket.fxcontrols.autocomplete;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.controlsfx.control.textfield.AutoCompletionBinding.ISuggestionRequest;
import impl.org.controlsfx.autocompletion.SuggestionProvider;
import javafx.util.Callback;
/**
*
* @author thirdy
*
* @param <T>
*/
public class BlackmarketSuggestionProvider<T> implements Callback<ISuggestionRequest, Collection<T>>{
private final List<T> possibleSuggestions = new ArrayList<>();
private final Object possibleSuggestionsLock = new Object();
/**
* Add the given new possible suggestions to this SuggestionProvider
* @param newPossible
*/
public void addPossibleSuggestions(@SuppressWarnings("unchecked") T... newPossible){
addPossibleSuggestions(Arrays.asList(newPossible));
}
/**
* Add the given new possible suggestions to this SuggestionProvider
* @param newPossible
*/
public void addPossibleSuggestions(Collection<T> newPossible){
synchronized (possibleSuggestionsLock) {
possibleSuggestions.addAll(newPossible);
}
}
/**
* Remove all current possible suggestions
*/
public void clearSuggestions(){
synchronized (possibleSuggestionsLock) {
possibleSuggestions.clear();
}
}
@Override
public final Collection<T> call(final ISuggestionRequest request) {
List<T> suggestions = new ArrayList<>();
if(!request.getUserText().isEmpty()){
synchronized (possibleSuggestionsLock) {
for (T possibleSuggestion : possibleSuggestions) {
if(isMatch(possibleSuggestion, request)){
suggestions.add(possibleSuggestion);
}
}
}
} else {
synchronized (possibleSuggestionsLock) {
suggestions.addAll(possibleSuggestions);
}
}
// Collections.sort(suggestions, getComparator());
return suggestions;
}
/**
* Create a default suggestion provider based on the toString() method of the generic objects
* @param possibleSuggestions All possible suggestions
* @return
*/
public static <T> BlackmarketSuggestionProvider<T> create(Collection<T> possibleSuggestions){
return create(null, possibleSuggestions);
}
/**
* Create a default suggestion provider based on the toString() method of the generic objects
* using the provided stringConverter
*
* @param stringConverter A stringConverter which converts generic T into a string
* @param possibleSuggestions All possible suggestions
* @return
*/
public static <T> BlackmarketSuggestionProvider<T> create(Callback<T, String> stringConverter, Collection<T> possibleSuggestions){
BlackmarketSuggestionProvider<T> suggestionProvider = new BlackmarketSuggestionProvider<>(stringConverter);
suggestionProvider.addPossibleSuggestions(possibleSuggestions);
return suggestionProvider;
}
private Callback<T, String> stringConverter;
private final Comparator<T> stringComparator = new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
String o1str = stringConverter.call(o1);
String o2str = stringConverter.call(o2);
return o1str.compareTo(o2str);
}
};
/**
* Create a new SuggestionProviderString
* @param stringConverter
*/
public BlackmarketSuggestionProvider(Callback<T, String> stringConverter){
this.stringConverter = stringConverter;
// In case no stringConverter was provided, use the default strategy
if(this.stringConverter == null){
this.stringConverter = new Callback<T, String>() {
@Override
public String call(T obj) {
return obj != null ? obj.toString() : ""; //$NON-NLS-1$
}
};
}
}
/**{@inheritDoc}*/
protected Comparator<T> getComparator() {
return stringComparator;
}
/**{@inheritDoc}*/
protected boolean isMatch(T suggestion, ISuggestionRequest request) {
String userTextLower = request.getUserText().toLowerCase();
String suggestionStr = suggestion.toString().toLowerCase();
return suggestionStr.contains(userTextLower)
&& !suggestionStr.equals(userTextLower);
}
}