package dnb.analyze.filetree;
import static java.nio.file.FileVisitResult.CONTINUE;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;
import org.apache.commons.collections.set.ListOrderedSet;
import dnb.data.filetree.Folder;
import dnb.data.filetree.Mp3File;
import dnb.data.filetree.NfoFile;
/**
* Builds the tree structure with mp3 file leafs - unnecessary folders & files are skipped.
* !!! Non-ambigous Nfo files are read & stored in the structure
* An arbitrary amount of categorizing parent folder may exist
* CategoryA-Folder
* |
* - SubcategoryA:A-Folder
* | |
* | - Mp3-Containing-Folder
* |
* - SubcategoryA:A-Folder
* // XXX refactor: generalize: remove file(Mp3File)
*/
public class Mp3FileTreeBuilder extends SimpleFileVisitor<Path> {
public static interface Reporter {
public void start(final String absolutePath, final boolean recreate);
public void finish(final String absolutePath);
public void file(final Mp3File file);
public void file(final NfoFile file);
public void fileFolder(final Folder f);
}
private final PathMatcher matcher;
private final Folder virtualRoot;
private Reporter reporter = new Reporter() {
/**
* Indicates scan start.
* @param recreate <code>true</code> is passed when the subtree already exists & thus will be deleted at start
*/
@Override public void start(final String absolutePath, final boolean recreate) {}
/** Indicates scan finish. */
@Override public void finish(final String absolutePath) {}
/**
* Indicates that an nfo file has been added.
* @param file a non-<code>null</code> <code>NfoFile</code> instance
*/
@Override public void file(final NfoFile file) {}
/**
* Indicates that an mp3 file has been added.
* @param file a non-<code>null</code> <code>NfoFile</code> instance
*/
@Override public void file(final Mp3File file) {}
/**
* Indicates that a <code>Folder</code> containing either mp3 or nfo files has been added.
* @param f a non-<code>null</code> <code>Folder</code> instance
*/
@Override public void fileFolder(final Folder f) {}
};
private int mp3FileCount = 0;
private int nfoFileCount = 0;
private static final String PATH_SEP = System.getProperty("file.separator");
private final ListOrderedSet fileFolders = new ListOrderedSet();
/**
* Creates a visitor, visits the path and adds it to the given virtual root.
* @param virtualRoot
* @param absolutePath
*/
public Mp3FileTreeBuilder() {
matcher = FileSystems.getDefault().getPathMatcher("glob:*.{mp3,nfo}");
this.virtualRoot = new Folder(null);
}
public void clear() {
virtualRoot.clear();
fileFolders.clear();
mp3FileCount = 0;
nfoFileCount = 0;
}
/**
* Append the current paht to the contained path.
* @param absolutePath
*/
public void appendPath(String absolutePath) {
Path path = FileSystems.getDefault().getPath(absolutePath);
Folder root = fromPath(path, true); // get root
root.setScanDate(new Date()); // and set current scan date
if (!root.isEmpty()) {
reporter.start(absolutePath, true);
root.clear();
} else {
reporter.start(absolutePath, false);
}
Files.walkFileTree(path, this); // populate it
reporter.finish(absolutePath);
}
@Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
Path name = file.getName();
if (name != null && matcher.matches(name)) {
// got an mp3
addFile(file, attrs);
}
}
return CONTINUE;
}
private Folder fromPath(Path name, boolean appendLastAsFolder) {
String rt = name.getRoot().toString();
if (rt.endsWith(PATH_SEP)) {
rt = rt.substring(0, rt.length() - PATH_SEP.length());
}
Folder cur = virtualRoot.getSubNode(rt);
Path cpt;
final int li = name.getNameCount() - 1;
// build subnode tree & add last node
for (int i = 0; i < li; i++) {
cpt = name.getName(i);
cur = cur.getSubNode(cpt.toString());
}
if (appendLastAsFolder) {
cur = cur.getSubNode(name.getName(li).toString());
}
return cur;
}
private void addFile(Path name, BasicFileAttributes attrs) {
final int li = name.getNameCount() - 1;
Folder cur = fromPath(name, false);
if(!fileFolders.contains(cur)) {
fileFolders.add(cur);
reporter.fileFolder(cur);
}
Path fil = name.getName(li);
if (fil.toString().toLowerCase().endsWith(".mp3")) {
mp3FileCount++;
Mp3File f = new Mp3File(fil.toString(), attrs.size());
cur.add(f);
reporter.file(f);
} else {
nfoFileCount++;
NfoFile f = new NfoFile(fil.toString(), attrs.size());
cur.add(f);
reporter.file(f);
}
}
public ListOrderedSet getFileFolders() {
return fileFolders;
}
public Folder getVirtualRoot() {
return virtualRoot;
}
public int getMp3FileCount() {
return mp3FileCount;
}
public int getNfoFileCount() {
return nfoFileCount;
}
public Reporter getReporter() {
return reporter;
}
public void setReporter(Reporter reporter) {
this.reporter = reporter;
}
}