package com.openfarmanager.android.core.archive;
import com.openfarmanager.android.filesystem.filter.ArchiveFilter;
import com.openfarmanager.android.filesystem.filter.FilterFactory;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import static com.openfarmanager.android.utils.Extensions.isNullOrEmpty;
public class ArchiveScanner {
private File mRoot;
private LinkedList<ArchiveFilter> mFilters;
public static final ArchiveScanner sInstance;
static {
sInstance = new ArchiveScanner();
}
private ArchiveScanner() {
mRoot = File.createRoot();
mFilters = new LinkedList<ArchiveFilter>();
mFilters.add(FilterFactory.createArchiveDirectoryUpFilter());
mFilters.add(FilterFactory.createArchiveAlphabeticFilter());
}
public final Comparator<File> mComparator = new Comparator<File>() {
public int compare(File f1, File f2) {
int result = 0;
for (ArchiveFilter filter : mFilters) {
if ((result = filter.doFilter(f1, f2)) != 0) {
return result;
}
}
return result;
}
};
public File root() {
return mRoot;
}
public void clearArchive() {
mRoot.mChildren = null;
}
public static class File {
private String mName;
private boolean mIsDirectory;
private long mSize;
private boolean mUp;
private File mParent;
private List<File> mChildren;
private boolean mRoot;
private int mChildFilesCount;
public File(File file) {
this (file.getName(), file.isDirectory(), file.getSize(), file.getParent(), file.isUpNavigator(), file.isRoot());
mChildren = file.getChildren();
}
private File(String name, boolean isDirectory, long size, File parent) {
mName = name;
mIsDirectory = isDirectory;
mSize = size;
mParent = parent;
mUp = false;
mRoot = false;
mChildFilesCount = -1;
}
private File(String name, boolean isDirectory, long size, File parent, boolean up, boolean root) {
this(name, isDirectory, size, parent);
mUp = up;
mRoot = root;
}
public static File createRoot() {
return new File("/", true, 0, null, false, true);
}
public static File createUpperNode(File parent) {
return new File("..", false, 0, parent, true, false);
}
public void addNode(String name, boolean isDirectory, long size) {
File child = new File(name, isDirectory, size, this);
if (mChildren == null) {
mChildren = new LinkedList<File>();
}
mChildren.add(child);
}
public void processFile(String path, long fileSize) {
if (isNullOrEmpty(path)) {
return;
}
String fullPath = path.replace("\\", "/");
if (fullPath.contains(java.io.File.separator)) {
String[] names = fullPath.split(java.io.File.separator);
String directoryName = names[0];
if (findDirectory(directoryName) == null) {
addNode(directoryName, true, 0);
}
File node = findDirectory(directoryName);
node.processFile(fullPath.substring(directoryName.length() + 1), fileSize);
} else {
addNode(fullPath, false, fileSize);
}
}
/**
* Count files (including current file and excluding directories).
*
* @return number of files in current file tree.
*/
public int countFiles() {
if (mChildFilesCount != -1) {
return mChildFilesCount;
}
mChildFilesCount = 1;
if (!isDirectory()) {
return mChildFilesCount;
}
for (File child : mChildren) {
if (!child.isDirectory()) {
mChildFilesCount++;
} else {
mChildFilesCount += child.countFiles();
}
}
return mChildFilesCount;
}
/**
* Find file recursively.
*
* @param name name of file to find
* @return file with name <code>fileName</code> or <code>null</code>, if file with specified name can't be found.
*/
public File findFile(String name) {
String fileName = name.replace("\\", "/");
if (getName().equals(fileName)) {
return this;
}
if (!isDirectory() && fileName.equals(getFullPath())) {
return this;
}
if (mChildren == null) {
return null;
}
for (File child : mChildren) {
if (child.getFullPath().equals(fileName)) {
return child;
}
if (child.isDirectory()) {
File childFile = child.findFile(fileName);
if (childFile != null) {
return childFile;
}
}
}
return null;
}
public File findInTree(String fileName) {
fileName = fileName.replace("//", "");
File parent = getParent();
if (parent != null) {
if (parent.getFullPath().equals(fileName)) {
return parent;
} else {
return parent.findInTree(fileName);
}
}
return null;
}
public File findDirectory(String directoryName) {
if (mChildren == null) {
return null;
}
for (File child : mChildren) {
if (child.isDirectory() && child.getName().equals(directoryName)) {
return child;
}
}
return null;
}
public void sort(List<File> filesToSort) {
if (filesToSort != null) {
Collections.sort(filesToSort, ArchiveScanner.sInstance.mComparator);
}
}
public String getName() {
return mName;
}
public boolean isDirectory() {
return mIsDirectory;
}
public long getSize() {
return mSize;
}
public File getParent() {
return mParent;
}
public List<File> getChildren() {
return mChildren;
}
/**
* Get path diff when extracting sub folder from archive.
*
* @param file file to be extracted from archive.
* @return sub-path within current working directory.
*/
public String getSubDirectoryPath(File file) {
String fullSubPath = getFullDirectoryPath();
String fullPath = file.getFullDirectoryPath();
return fullPath.substring(fullSubPath.trim().length() > 0 ? fullSubPath.length() - 1 : 0);
}
public String getFullDirectoryPath() {
StringBuilder fullPath = new StringBuilder();
File parent = getParent();
while (parent != null && !parent.isRoot()) {
fullPath.insert(0, parent.getName() + "/");
parent = parent.getParent();
}
return fullPath.toString();
}
public String getFullPath() {
StringBuilder fullPath = new StringBuilder(mName);
File parent = getParent();
while (parent != null && !parent.isRoot()) {
fullPath.insert(0, parent.getName() + "/");
parent = parent.getParent();
}
return fullPath.toString();
}
public List<File> getSortedChildren() {
sort(mChildren);
return mChildren;
}
public boolean isUpNavigator() {
return mUp;
}
public boolean isRoot() {
return mRoot;
}
}
}