package org.jabref.model.entry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jabref.model.strings.StringUtil;
/**
* Represents a list of keyword chains.
* For example, "Type > A, Type > B, Something else".
*/
public class KeywordList implements Iterable<Keyword> {
private final List<Keyword> keywordChains;
public KeywordList() {
keywordChains = new ArrayList<>();
}
public KeywordList(Collection<Keyword> keywordChains) {
this.keywordChains = new ArrayList<>();
keywordChains.forEach(this::add);
}
public KeywordList(List<String> keywordChains) {
this(keywordChains.stream().map(Keyword::new).collect(Collectors.toList()));
}
public KeywordList(String... keywordChains) {
this(Arrays.stream(keywordChains).map(Keyword::new).collect(Collectors.toList()));
}
public KeywordList(Keyword... keywordChains) {
this(Arrays.asList(keywordChains));
}
public static KeywordList parse(String keywordString, Character delimiter, Character hierarchicalDelimiter) {
if (StringUtil.isBlank(keywordString)) {
return new KeywordList();
}
KeywordList keywordList = new KeywordList();
StringTokenizer tok = new StringTokenizer(keywordString, delimiter.toString());
while (tok.hasMoreTokens()) {
String chain = tok.nextToken();
Keyword chainRoot = Keyword.of(chain.split(hierarchicalDelimiter.toString()));
keywordList.add(chainRoot);
}
return keywordList;
}
/**
* @param keywordString a String of keywordChains
* @return an parsed list containing the keywordChains
*/
public static KeywordList parse(String keywordString, Character delimiter) {
return parse(keywordString, delimiter, Keyword.DEFAULT_HIERARCHICAL_DELIMITER);
}
public KeywordList createClone() {
return new KeywordList(this.keywordChains);
}
public void replaceAll(KeywordList keywordsToReplace, Keyword newValue) {
Objects.requireNonNull(newValue);
// Remove keywordChains which should be replaced
int foundPosition = -1; // remember position of the last found keyword
for (Keyword specialFieldKeyword : keywordsToReplace) {
int pos = keywordChains.indexOf(specialFieldKeyword);
if (pos >= 0) {
foundPosition = pos;
keywordChains.remove(pos);
}
}
// Add new keyword at right position
if (foundPosition == -1) {
add(newValue);
} else {
keywordChains.add(foundPosition, newValue);
}
}
public void removeAll(KeywordList keywordsToRemove) {
keywordChains.removeAll(keywordsToRemove.keywordChains);
}
public boolean add(Keyword keyword) {
if (contains(keyword)) {
return false; // Don't add duplicate keywordChains
}
return keywordChains.add(keyword);
}
/**
* Keywords are separated by the given delimiter and an additional space, i.e. "one, two".
*/
public String getAsString(Character delimiter) {
return keywordChains.stream().map(Keyword::toString).collect(Collectors.joining(delimiter + " "));
}
public void add(String keywordsString) {
add(new Keyword(keywordsString));
}
@Override
public Iterator<Keyword> iterator() {
return keywordChains.iterator();
}
public int size() {
return keywordChains.size();
}
public boolean isEmpty() {
return keywordChains.isEmpty();
}
public boolean contains(Keyword o) {
return keywordChains.contains(o);
}
public boolean remove(Keyword o) {
return keywordChains.remove(o);
}
public boolean remove(String keywordsString) {
return keywordChains.remove(new Keyword(keywordsString));
}
public void addAll(KeywordList keywordsToAdd) {
keywordChains.addAll(keywordsToAdd.keywordChains);
}
public void retainAll(KeywordList keywordToRetain) {
keywordChains.retainAll(keywordToRetain.keywordChains);
}
public void clear() {
keywordChains.clear();
}
public Keyword get(int index) {
return keywordChains.get(index);
}
public Stream<Keyword> stream() {
return keywordChains.stream();
}
@Override
public String toString() {
return getAsString(',');
}
public Set<String> toStringList() {
return keywordChains.stream().map(Keyword::toString).collect(Collectors.toSet());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if ((o == null) || (getClass() != o.getClass())) {
return false;
}
KeywordList keywords1 = (KeywordList) o;
return Objects.equals(keywordChains, keywords1.keywordChains);
}
@Override
public int hashCode() {
return Objects.hash(keywordChains);
}
}