package net.sf.cotta.system;
import net.sf.cotta.PathContent;
import net.sf.cotta.PathSeparator;
import net.sf.cotta.TDirectoryNotFoundException;
import net.sf.cotta.TFileNotFoundException;
import net.sf.cotta.TIoException;
import net.sf.cotta.TPath;
import net.sf.cotta.memory.ListingOrder;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HashBasedDirectoryIndex<F extends FileContent> extends AbstractDirectoryIndex<F> {
private final Map<TPath, DirectoryContent> createDirs = new HashMap<TPath, DirectoryContent>();
private final Map<TPath, F> createFiles = new HashMap<TPath, F>();
public HashBasedDirectoryIndex(ContentManager<F> contentManager) {
super(contentManager);
init();
}
public HashBasedDirectoryIndex(PathSeparator separator, ListingOrder order, ContentManager<F> contentManager) {
super(separator, order, contentManager);
init();
}
private void init() {
createDirs.put(TPath.parse("/"), new DirectoryContent());
createDirs.put(TPath.parse("."), new DirectoryContent());
}
public boolean fileExists(TPath path) {
return createFiles.containsKey(path);
}
public boolean dirExists(TPath path) {
if (createDirs.containsKey(path)) {
return true;
}
return false;
}
public PathContent list(TPath path) {
DirectoryContent content = createDirs.get(path);
PathContent result = new PathContent(content.dirs(), content.files());
sort(result.files());
sort(result.dirs());
return result;
}
public F createFile(TPath path) throws TIoException {
validateBeforeCreateFile(path);
if (!dirExists(path.parent())) {
throw new TIoException(path, "parent needs to be created first");
}
createDirs.get(path.parent()).addFile(path);
F fileContent = contentManager.createFileContent();
createFiles.put(path, fileContent);
return fileContent;
}
public void deleteFile(TPath path) throws TFileNotFoundException {
if (!createFiles.containsKey(path)) {
throw new TFileNotFoundException(path);
}
createFiles.remove(path);
createDirs.get(path.parent()).removeFile(path);
}
public void moveFile(TPath source, TPath destination) throws TIoException {
F file = createFiles.remove(source);
createFiles.put(destination, file);
createDirs.get(source.parent()).removeFile(source);
createDirs.get(destination.parent()).addFile(destination);
}
public void createDir(TPath path) throws TIoException {
validateBeforeCreateDir(path);
ensureDirExists(path.parent()).addDir(path);
createDirs.put(path, new DirectoryContent());
}
public void deleteDir(TPath path) throws TIoException {
if (!dirExists(path)) {
throw new TDirectoryNotFoundException(path);
}
DirectoryContent directoryContent = createDirs.get(path);
if (!directoryContent.isEmpty()) {
throw new TIoException(path, "Directory not empty");
}
createDirs.remove(path);
createDirs.get(path.parent()).removeDir(path);
}
public void moveDir(TPath source, TPath destination) throws TIoException {
createDir(destination);
PathContent content = list(source);
moveSubDirectories(content.dirs(), destination);
moveFiles(content.files(), destination);
deleteDir(source);
}
public F fileContent(TPath path) {
return createFiles.get(path);
}
private DirectoryContent ensureDirExists(TPath dir) throws TIoException {
if (!dirExists(dir)) {
createDir(dir);
}
return createDirs.get(dir);
}
private void moveSubDirectories(List<TPath> directories, TPath destination) throws TIoException {
for (TPath directory : directories) {
moveDir(directory, destination.join(directory.lastElementName()));
}
}
private void moveFiles(List<TPath> files, TPath destination) throws TIoException {
for (TPath file : files) {
moveFile(file, destination.join(file.lastElementName()));
}
}
public static class DirectoryContent {
private Map<String, TPath> dirs = new HashMap<String, TPath>();
private Map<String, TPath> files = new HashMap<String, TPath>();
public Collection<TPath> dirs() {
return dirs.values();
}
public void addDir(TPath directory) {
dirs.put(directory.lastElementName(), directory);
}
public void addFile(TPath file) {
files.put(file.lastElementName(), file);
}
public Collection<TPath> files() {
return files.values();
}
public boolean isEmpty() {
return files.isEmpty() && dirs.isEmpty();
}
public void removeFile(TPath file) {
files.remove(file.lastElementName());
}
public void removeDir(TPath directory) {
dirs.remove(directory.lastElementName());
}
}
}