175 lines
4.2 KiB
Java
175 lines
4.2 KiB
Java
package net.filebot.util;
|
|
|
|
import static java.nio.charset.StandardCharsets.*;
|
|
import static java.util.Collections.*;
|
|
import static java.util.stream.Collectors.*;
|
|
import static net.filebot.Logging.*;
|
|
import static net.filebot.util.FileUtilities.*;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.net.URI;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.InvalidPathException;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.StandardOpenOption;
|
|
import java.util.AbstractSet;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Set;
|
|
import java.util.Spliterator;
|
|
import java.util.stream.Stream;
|
|
|
|
public class FileSet extends AbstractSet<Path> {
|
|
|
|
private static final int ROOT_LEVEL = -1;
|
|
|
|
private final Map<Path, FileSet> folders = new HashMap<Path, FileSet>(4, 2);
|
|
private final Set<Path> files = new HashSet<Path>(4, 2);
|
|
|
|
private boolean add(Path e, int depth) {
|
|
// add new leaf element
|
|
if (e.getNameCount() - 1 == depth) {
|
|
return files.add(e.getFileName());
|
|
}
|
|
|
|
// add new node element
|
|
return folders.computeIfAbsent(depth == ROOT_LEVEL ? e.getRoot() : e.getName(depth), k -> new FileSet()).add(e, depth + 1);
|
|
}
|
|
|
|
@Override
|
|
public boolean add(Path e) {
|
|
return add(e, ROOT_LEVEL);
|
|
}
|
|
|
|
public boolean add(File e) {
|
|
return add(e.toPath());
|
|
}
|
|
|
|
public boolean add(String e) {
|
|
return add(Paths.get(e));
|
|
}
|
|
|
|
private boolean contains(Path e, int depth) {
|
|
// leaf element
|
|
if (e.getNameCount() - 1 == depth) {
|
|
return files.contains(e.getFileName());
|
|
}
|
|
|
|
// node element
|
|
if (e.getNameCount() - 1 > depth) {
|
|
FileSet subSet = folders.get(depth == ROOT_LEVEL ? e.getRoot() : e.getName(depth));
|
|
if (subSet != null) {
|
|
return subSet.contains(e, depth + 1);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean contains(Path e) {
|
|
return contains(e, ROOT_LEVEL);
|
|
};
|
|
|
|
@Override
|
|
public boolean contains(Object e) {
|
|
return contains(getPath(e));
|
|
};
|
|
|
|
protected Path getPath(Object path) {
|
|
if (path instanceof Path) {
|
|
return (Path) path;
|
|
}
|
|
if (path instanceof File) {
|
|
return ((File) path).toPath();
|
|
}
|
|
if (path instanceof String) {
|
|
return Paths.get((String) path);
|
|
}
|
|
if (path instanceof URI) {
|
|
return Paths.get((URI) path);
|
|
}
|
|
return Paths.get(path.toString());
|
|
}
|
|
|
|
public Map<Path, List<Path>> getRoots() {
|
|
if (folders.size() != 1 || files.size() > 0) {
|
|
return emptyMap();
|
|
}
|
|
|
|
Entry<Path, FileSet> entry = folders.entrySet().iterator().next();
|
|
Path parent = entry.getKey();
|
|
Map<Path, List<Path>> next = entry.getValue().getRoots();
|
|
if (next.size() > 0) {
|
|
// resolve children
|
|
return next.entrySet().stream().collect(toMap(it -> {
|
|
return parent.resolve(it.getKey());
|
|
}, it -> it.getValue()));
|
|
}
|
|
|
|
// resolve children
|
|
return folders.entrySet().stream().collect(toMap(it -> it.getKey(), it -> it.getValue().stream().collect(toList())));
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return folders.values().stream().mapToInt(f -> f.size()).sum() + files.size();
|
|
}
|
|
|
|
@Override
|
|
public Stream<Path> stream() {
|
|
Stream<Path> descendants = folders.entrySet().stream().flatMap(node -> {
|
|
return node.getValue().stream().map(f -> {
|
|
return node.getKey().resolve(f);
|
|
});
|
|
});
|
|
|
|
Stream<Path> children = files.stream();
|
|
|
|
return Stream.concat(descendants, children);
|
|
}
|
|
|
|
@Override
|
|
public Spliterator<Path> spliterator() {
|
|
return stream().spliterator();
|
|
}
|
|
|
|
@Override
|
|
public Iterator<Path> iterator() {
|
|
return stream().iterator();
|
|
}
|
|
|
|
@Override
|
|
public boolean remove(Object o) {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
folders.values().forEach(FileSet::clear);
|
|
folders.clear();
|
|
files.clear();
|
|
}
|
|
|
|
public void load(File f) throws IOException {
|
|
for (String path : readLines(f)) {
|
|
try {
|
|
add(path);
|
|
} catch (InvalidPathException e) {
|
|
debug.warning(e::toString);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void append(File f, Collection<?>... paths) throws IOException {
|
|
Files.write(f.toPath(), Stream.of(paths).flatMap(Collection::stream).map(this::getPath).filter(it -> !contains(it)).map(Path::toString).collect(toList()), UTF_8, StandardOpenOption.APPEND);
|
|
}
|
|
|
|
}
|