/*-
* Copyright (C) 2009 Peter Baldwin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.peterbaldwin.vlcremote.model;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("serial")
public class Directory extends ArrayList<File> implements Comparator<File> {
public static final String UNIX_DIRECTORY = "/";
public static final String WINDOWS_ROOT_DIRECTORY = "";
public static String ROOT_DIRECTORY = UNIX_DIRECTORY;
private final Map<String, Set<String>> realDirMap;
public Directory() {
realDirMap = new HashMap<String, Set<String>>();
}
public Directory(int capacity) {
super(capacity);
realDirMap = new HashMap<String, Set<String>>();
}
/**
* Adds a file to the directory. If the file is a library, a library name or
* a library directory, then the real directory given will be cached.
* @param file File to add
* @param realDir real directory of file, can be null if the file's path is
* already valid (e.g. for a standard file or directory)
*/
public void addFile(File file, String realDir) {
if(file.isLibraryDir() || file.isLibrary() || file.isLibraryName()) {
boolean keyExists = realDirMap.containsKey(file.getName());
if(!keyExists) {
realDirMap.put(file.getName(), new HashSet<String>(4));
}
realDirMap.get(file.getName()).add(File.getNormalizedPath(realDir));
if(keyExists) {
return;
}
}
add(file);
}
public Set<String> getRealPaths(String dirName) {
return realDirMap.get(dirName);
}
/**
* Get the path to the current directory.
* The path is determined from existing files in the directory or the parent
* entry if it exists. If there are no items in the directory and there is
* no parent entry, then the ROOT_DIRECTORY will be returned.
* @return current directory path or ROOT_DIRECTORY
*/
public String getPath() {
String tmpRoot = null;
for (File file : this) {
String path = file.getPath();
if (file.isParent()) {
if(path != null && path.endsWith("..")) {
final int length = path.length() - "..".length();
return File.getNormalizedPath(path.substring(0, length));
}
} else {
path = File.getNormalizedPath(file.getPath().concat("/.."));
if(tmpRoot == null) {
tmpRoot = path; // ensure two directory entries are checked
continue; // for same root. if not then root is drive
}
return tmpRoot.equals(path) ? path : ROOT_DIRECTORY;
}
}
return ROOT_DIRECTORY;
}
/**
* Compares two Files that are to be sorted with directories being displayed
* before files. The parent entry will be first if present, then the
* directories and then files.
* @param firstFile
* @param secondFile
* @return a negative integer, zero, or a positive integer as the first
* argument is less than, equal to, or greater than the second.
*/
@Override
public int compare(File firstFile, File secondFile) {
if((firstFile.isLibrary() || firstFile.isParent()) && !secondFile.isLibrary()) {
return -1;
}
if(!firstFile.isLibrary() && (secondFile.isLibrary() || secondFile.isParent())) {
return 1;
}
boolean isFirstDir = firstFile.isDirectory() || firstFile.isLibraryDir();
boolean isSecondDir = secondFile.isDirectory() || secondFile.isLibraryDir();
// parent always first
if(isFirstDir && firstFile.isParent() && isSecondDir && secondFile.isParent()) {
return 0;
}
if(isFirstDir && firstFile.isParent()) {
return -1;
}
if(isSecondDir && secondFile.isParent()) {
return 1;
}
// then directories next
if(isFirstDir && !isSecondDir) {
return -1;
}
if(isSecondDir && !isFirstDir) {
return 1;
}
// then files
return firstFile.getName().compareToIgnoreCase(secondFile.getName());
}
public Comparator<File> getCaseInsensitiveComparator() {
return new CaseInsensitiveComparator();
}
private final static class CaseInsensitiveComparator implements Comparator<File> {
@Override
public int compare(File lhs, File rhs) {
if((lhs.isLibrary() || lhs.isParent()) && !rhs.isLibrary()) {
return -1;
}
if(!lhs.isLibrary() && (rhs.isLibrary() || rhs.isParent())) {
return 1;
}
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
}
}