package org.smoothbuild.io.fs.base;
import static com.google.common.base.Preconditions.checkState;
import static org.smoothbuild.io.fs.base.Path.root;
import static org.smoothbuild.io.fs.base.PathState.NOTHING;
import java.util.ArrayDeque;
import java.util.Iterator;
import com.google.common.collect.ImmutableList;
public class RecursiveFilesIterable implements Iterable<Path> {
private final FileSystem fileSystem;
private final Path rootDir;
public static Iterable<Path> recursiveFilesIterable(FileSystem fileSystem, Path dir) {
switch (fileSystem.pathState(dir)) {
case FILE:
throw new IllegalArgumentException("Path " + dir + " is not a dir but a file.");
case DIR:
return new RecursiveFilesIterable(fileSystem, dir);
case NOTHING:
return ImmutableList.of();
default:
throw new RuntimeException("Unexpected case: " + fileSystem.pathState(dir));
}
}
private RecursiveFilesIterable(FileSystem fileSystem, Path rootDir) {
this.fileSystem = fileSystem;
this.rootDir = rootDir;
}
public Iterator<Path> iterator() {
return new RecursiveFilesIterator();
}
private class RecursiveFilesIterator implements Iterator<Path> {
private final ArrayDeque<Path> dirStack;
private final ArrayDeque<Path> fileStack;
private Path nextFile;
public RecursiveFilesIterator() {
this.dirStack = new ArrayDeque<>();
this.fileStack = new ArrayDeque<>();
this.dirStack.push(root());
this.nextFile = fetchNextFile();
}
public boolean hasNext() {
return nextFile != null;
}
public Path next() {
checkState(hasNext());
Path result = nextFile;
nextFile = fetchNextFile();
return result;
}
private Path fetchNextFile() {
while (!fileStack.isEmpty() || !dirStack.isEmpty()) {
if (fileStack.isEmpty()) {
Path dir = dirStack.remove();
for (Path name : fileSystem.files(rootDir.append(dir))) {
fileStack.push(dir.append(name));
}
} else {
Path file = fileStack.remove();
switch (fileSystem.pathState(rootDir.append(file))) {
case FILE:
return file;
case DIR:
dirStack.push(file);
break;
case NOTHING:
throw new RuntimeException("Unexpected case: " + NOTHING);
default:
throw new RuntimeException(
"Unexpected case: " + fileSystem.pathState(rootDir.append(file)));
}
}
}
return null;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}