package com.limegroup.gnutella.gui.init;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.util.LimitedList;
import com.limegroup.gnutella.util.Pair;
import com.limegroup.gnutella.util.StringUtils;
/**
* At either run time or the first time the client is run, this class
* will scan the entire hard drive searching for files with particular
* file extensions (like .mp3). It will keep track of the directories
* in which those files exist, and will return the top 5 directories.
* The top five are chosen by some combination of number of files and
* memory.
*
* @author rsoule
*/
public class FileScan {
private int MEM_WEIGHT = 1;
private int NUM_WEIGHT = 1;
private int MAX_DEPTH = 3;
private String[] _extensions;
private String[] _filters;
private LimitedList _list;
public FileScan() {
_list = new LimitedList();
_filters = new String[0];
String exts = SharingSettings.EXTENSIONS_TO_SHARE.getValue();
_extensions = StringUtils.split(exts, ";");
}
/**
* Sets the shared extensions to use for searching.
*/
public void setExtensions(String[] e) {
_extensions = e;
}
/**
* Sets the words to use as filters for determining potential
* shared directories.
*/
public void setFilters(String[] f) {
_filters = f;
}
/**
* Returns the list of directories containing shared file
* types as an array of strings.
*/
public String[] getListAsArray() {
Object[] objs = _list.getAllElements();
int len = objs.length;
Pair p;
File f;
String[] files = new String[len];
for (int i = 0; i < len; i++) {
if (objs[i] != null) {
p = (Pair)objs[i];
f = (File)p.getElement();
try {
files[i] = f.getCanonicalPath();
} catch (IOException ioe) {
files[i] = "";
}
}
}
return files;
}
/**
* Returns the list of directories containing shared file
* types as one long strings.
*/
public String getListAsString() {
Object[] objs = _list.getAllElements();
int len = objs.length;
String files = "";
for (int i = 0; i < len; i++) {
if (objs[i] != null) {
Pair p = (Pair)objs[i];
File f = (File)p.getElement();
try {
files += f.getCanonicalPath();
files += ";";
} catch (IOException ioe) {
}
}
}
return files;
}
/**
* Scans the directory associated with the string parameter
* for directories containing shared file types.
*/
public void scan(String pathname) {
scan(pathname, MAX_DEPTH);
}
/**
* Does the internal scanning for directories containing
* shared file types.
*/
private void scan(String pathname, int depth) {
if (depth == 0)
return;
depth--;
File file = new File(pathname);
if (!file.isDirectory())
return;
File[] files = listFiles(file);
int num_files = files.length;
for (int i = 0; i < num_files; i++) {
File f = files[i];
if (f.isDirectory()) {
try {
String path = f.getCanonicalPath();
addDirectory(path);
scan(path, depth);
} catch (IOException ioe) {
}
//addDirectory(f.getCanonicalPath());
//scan(f.getAbsolutePath(), depth);
}
}
}
/**
* .
*/
public void scan(String[] pathnames) {
scan(pathnames, MAX_DEPTH);
}
/**
* .
*/
public void scan(String[] pathnames, int depth) {
if (depth == 0)
return;
depth--;
String pathname;
for (int j = 0; j < pathnames.length; j++) {
pathname = pathnames[j];
File file = new File(pathname);
if (file.isDirectory()) {
File[] files = listFiles(file);
int num_files = files.length;
for (int i = 0; i < num_files; i++) {
File f = files[i];
if (f.isDirectory()) {
try {
String subDirPath = f.getCanonicalPath();
addDirectory(subDirPath);
scan(subDirPath);
} catch (IOException ioe) {
}
}
}
}
}
}
/**
* Adds a directory to the list of potential directories
* to share.
*/
private void addDirectory(String pathname) {
File dir = new File(pathname);
if (!dir.isDirectory())
return;
int mem = 0;
int num = 0;
if (!hasFilter(pathname)) {
File[] files = listFiles(dir);
int num_files = files.length;
for (int i = 0; i < num_files; i++) {
File f = files[i];
String name = f.getName();
if (hasExtension(name)) {
mem += f.length();
num++;
}
}
}
int key = calculateKey(num, mem);
_list.add(new Pair(key, dir), key);
}
/**
* Calculates the "key," or weighted value, that a directory
* should have based on the number of files and the size of
* those files.
*/
private int calculateKey(int num_files, int size_files) {
int key = (num_files * NUM_WEIGHT) + (size_files * MEM_WEIGHT);
return key;
}
/**
* Determines whether or not the file denoted by this
* pathname has a filter associated with it.
*/
private boolean hasFilter(String pathname) {
pathname = pathname.toLowerCase(Locale.US);
int length = _filters.length;
for (int i = 0; i < length; i++) {
String curFilter = _filters[i].toLowerCase(Locale.US);
if (pathname.indexOf(curFilter) != -1)
return true;
}
return false;
}
/**
* Determines if the file denoted by the "filename" parameter
* has a shared extension.
*/
private boolean hasExtension(String filename) {
int begin = filename.lastIndexOf(".") + 1;
if (begin == 0) // file has no extension
return false; // always not shared ?
// Should we also share files with only extensions, i.e. those
// starting with a dot like ".rc" which are "hidden" on Unix
// if not, we should exclude the case where begin == 1 too...
// (A leading dot does not denote an extension but a special name).
int end = filename.length();
String ext = filename.substring(begin, end);
int length = _extensions.length;
for (int i = 0; i < length; i++) {
if (ext.equalsIgnoreCase(_extensions[i])) {
return true;
}
}
return false;
}
/**
* Returns an array of File objects representing
* the files and directories in the directory
* denoted in the "dir" parameter.
* @requires the File parameter must be a directory.
* @param dir a directory File object.
*/
private File[] listFiles(File dir) {
String [] fnames = dir.list();
if (fnames == null)
return new File[0];
File[] theFiles = new File[fnames.length];
for (int i = 0; i < fnames.length; i++) {
theFiles[i] = new File(dir, fnames[i]);
}
return theFiles;
}
// public static void main(String argc[]) {
// FileScan fs = new FileScan();
// String root = "C:\\";
// String[] filters = { "Recycle", "Incomplete", "LimeWire" };
// fs.setFilters(filters);
// fs.scan(root);
// //String[] dirs_ = fs.getListAsArray();
// String str = fs.getListAsString();
// System.out.println("found: " + str);
// }
}