package org.jabref.model.groups;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.jabref.model.FieldChange;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.KeywordList;
import org.jabref.model.strings.StringUtil;
/**
* Matches entries if a given field contains a specified word.
*/
public class WordKeywordGroup extends KeywordGroup implements GroupEntryChanger {
protected final Character keywordSeparator;
private final Set<String> searchWords;
private final boolean onlySplitWordsAtSeparator;
public WordKeywordGroup(String name, GroupHierarchyType context, String searchField,
String searchExpression, boolean caseSensitive, Character keywordSeparator,
boolean onlySplitWordsAtSeparator) {
super(name, context, searchField, searchExpression, caseSensitive);
this.keywordSeparator = keywordSeparator;
this.onlySplitWordsAtSeparator = onlySplitWordsAtSeparator;
this.searchWords = getSearchWords(searchExpression);
}
private static boolean containsCaseInsensitive(Set<String> searchIn, Collection<String> searchFor) {
for (String searchWord : searchFor) {
if (!containsCaseInsensitive(searchIn, searchWord)) {
return false;
}
}
return true;
}
private static boolean containsCaseInsensitive(Set<String> searchIn, String searchFor) {
for (String word : searchIn) {
if (word.equalsIgnoreCase(searchFor)) {
return true;
}
}
return false;
}
@Override
public List<FieldChange> add(List<BibEntry> entriesToAdd) {
Objects.requireNonNull(entriesToAdd);
List<FieldChange> changes = new ArrayList<>();
for (BibEntry entry : entriesToAdd) {
if (!contains(entry)) {
String oldContent = entry.getField(searchField).orElse("");
KeywordList wordlist = KeywordList.parse(oldContent, keywordSeparator);
wordlist.add(searchExpression);
String newContent = wordlist.getAsString(keywordSeparator);
entry.setField(searchField, newContent).ifPresent(changes::add);
}
}
return changes;
}
@Override
public List<FieldChange> remove(List<BibEntry> entriesToRemove) {
Objects.requireNonNull(entriesToRemove);
List<FieldChange> changes = new ArrayList<>();
for (BibEntry entry : entriesToRemove) {
if (contains(entry)) {
String oldContent = entry.getField(searchField).orElse("");
KeywordList wordlist = KeywordList.parse(oldContent, keywordSeparator);
wordlist.remove(searchExpression);
String newContent = wordlist.getAsString(keywordSeparator);
entry.setField(searchField, newContent).ifPresent(changes::add);
}
}
return changes;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof WordKeywordGroup)) {
return false;
}
WordKeywordGroup other = (WordKeywordGroup) o;
return getName().equals(other.getName())
&& (getHierarchicalContext() == other.getHierarchicalContext())
&& searchField.equals(other.searchField)
&& searchExpression.equals(other.searchExpression)
&& (caseSensitive == other.caseSensitive)
&& keywordSeparator == other.keywordSeparator
&& onlySplitWordsAtSeparator == other.onlySplitWordsAtSeparator;
}
@Override
public boolean contains(BibEntry entry) {
Set<String> content = getFieldContentAsWords(entry);
if (caseSensitive) {
return content.containsAll(searchWords);
} else {
return containsCaseInsensitive(content, searchWords);
}
}
private Set<String> getFieldContentAsWords(BibEntry entry) {
if (onlySplitWordsAtSeparator) {
return entry.getField(searchField)
.map(content -> KeywordList.parse(content, keywordSeparator).toStringList())
.orElse(Collections.emptySet());
} else {
return entry.getFieldAsWords(searchField);
}
}
private Set<String> getSearchWords(String searchExpression) {
if (onlySplitWordsAtSeparator) {
return KeywordList.parse(searchExpression, keywordSeparator).toStringList();
} else {
return new HashSet<>(StringUtil.getStringAsWords(searchExpression));
}
}
@Override
public AbstractGroup deepCopy() {
return new WordKeywordGroup(getName(), getHierarchicalContext(), searchField, searchExpression,
caseSensitive, keywordSeparator, onlySplitWordsAtSeparator);
}
@Override
public int hashCode() {
return Objects.hash(getName(),
getHierarchicalContext(),
searchField,
searchExpression,
caseSensitive,
keywordSeparator,
onlySplitWordsAtSeparator);
}
}