package org.jabref.logic.util.io;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.util.FileHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
class CiteKeyBasedFileFinder implements FileFinder {
private static final Log LOGGER = LogFactory.getLog(CiteKeyBasedFileFinder.class);
private final boolean exactKeyOnly;
CiteKeyBasedFileFinder(boolean exactKeyOnly) {
this.exactKeyOnly = exactKeyOnly;
}
@Override
public Map<BibEntry, List<Path>> findAssociatedFiles(List<BibEntry> entries, List<Path> directories, List<String> extensions) {
Objects.requireNonNull(directories);
Objects.requireNonNull(entries);
Map<BibEntry, List<Path>> result = new HashMap<>();
// First scan directories
Set<Path> filesWithExtension = findFilesByExtension(directories, extensions);
// Initialize Result-Set
for (BibEntry entry : entries) {
result.put(entry, new ArrayList<>());
}
// Now look for keys
nextFile:
for (Path file : filesWithExtension) {
String name = file.getFileName().toString();
int dot = name.lastIndexOf('.');
// First, look for exact matches:
for (BibEntry entry : entries) {
Optional<String> citeKey = entry.getCiteKeyOptional();
if ((citeKey.isPresent()) && !citeKey.get().isEmpty() && (dot > 0)
&& name.substring(0, dot).equals(citeKey.get())) {
result.get(entry).add(file);
continue nextFile;
}
}
// If we get here, we did not find any exact matches. If non-exact
// matches are allowed, try to find one:
if (!exactKeyOnly) {
for (BibEntry entry : entries) {
Optional<String> citeKey = entry.getCiteKeyOptional();
if ((citeKey.isPresent()) && !citeKey.get().isEmpty() && name.startsWith(citeKey.get())) {
result.get(entry).add(file);
continue nextFile;
}
}
}
}
return result;
}
/**
* Returns a list of all files in the given directories which have one of the given extension.
*/
public Set<Path> findFilesByExtension(List<Path> directories, List<String> extensions) {
Objects.requireNonNull(extensions, "Extensions must not be null!");
BiPredicate<Path, BasicFileAttributes> isFileWithCorrectExtension = (path, attributes) ->
!Files.isDirectory(path)
&& extensions.contains(FileHelper.getFileExtension(path).orElse(""));
Set<Path> result = new HashSet<>();
for (Path directory : directories) {
try (Stream<Path> files = Files.find(directory, Integer.MAX_VALUE, isFileWithCorrectExtension)) {
result.addAll(files.collect(Collectors.toSet()));
} catch (IOException e) {
LOGGER.error("Problem in finding files", e);
}
}
return result;
}
}