package com.github.marschall.memoryfilesystem; import java.io.IOException; import java.net.URI; import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.CollationKey; import java.text.Collator; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; final class SingletonPath extends ElementPath { private final String fileName; SingletonPath(MemoryFileSystem fileSystem, String fileName) { super(fileSystem); this.fileName = fileName; } @Override public boolean isAbsolute() { return false; } @Override public Path getRoot() { return null; } @Override public Path getFileName() { return this; } @Override public Path getParent() { return null; } @Override public int getNameCount() { return 1; } @Override public Path getName(int index) { if (index != 0) { throw new IllegalArgumentException("index must be 0 but was " + index); } return this; } @Override public Path subpath(int beginIndex, int endIndex) { if (beginIndex != 0) { throw new IllegalArgumentException("begin index must be 1"); } if (endIndex != 1) { throw new IllegalArgumentException("end index must be 1"); } return this; } @Override public boolean startsWith(String other) { Path path = this.getMemoryFileSystem().getPath(other); return this.isEqualPath((AbstractPath) path); } @Override public boolean endsWith(String other) { Path path = this.getMemoryFileSystem().getPath(other); return this.isEqualPath((AbstractPath) path); } @Override public Path normalize() { return this; } @Override public URI toUri() { return this.toAbsolutePath().toUri(); } @Override public Path toAbsolutePath() { return this.getMemoryFileSystem().getDefaultPath().resolve(this); } @Override public Path toRealPath(LinkOption... options) throws IOException { return this.getMemoryFileSystem().toRealPath(this, options); } @Override public Iterator<Path> iterator() { return Collections.<Path>singleton(this).iterator(); } @Override List<String> getNameElements() { return Collections.singletonList(this.fileName); } @Override String getNameElement(int index) { if (index != 0) { throw new IllegalArgumentException("index must be 0 but was " + index); } return this.fileName; } @Override String getLastNameElement() { return this.fileName; } @Override int compareToNonRoot(ElementPath other) { if (other.isAbsolute()) { return 1; } if (other.getNameCount() == 0) { return 1; } Collator collator = this.getMemoryFileSystem().getCollator(); int comparison = collator.compare(this.fileName, other.getNameElement(0)); if (comparison != 0) { return comparison; } if (other.getNameCount() > 1) { return -1; } else { return 0; } } @Override boolean startsWith(AbstractPath other) { return this.isEqualPath(other); } @Override boolean endsWith(AbstractPath other) { return this.isEqualPath(other); } private boolean isEqualPath(AbstractPath other) { if (other.isAbsolute()) { return false; } if (other.isRoot()) { return false; } if (other instanceof ElementPath) { ElementPath otherPath = (ElementPath) other; if (otherPath.getNameCount() != 1) { return false; } Collator collator = this.getMemoryFileSystem().getCollator(); return collator.equals(this.fileName, otherPath.getLastNameElement()); } else { throw new IllegalArgumentException("can't check for #startsWith against " + other); } } @Override Path resolve(ElementPath other) { List<String> newNameElement = CompositeList.create(this.getNameElements(), other.getNameElements()); return AbstractPath.createRelative(this.getMemoryFileSystem(), newNameElement); } @Override Path resolveSibling(AbstractPath other) { return other; } @Override boolean isRoot() { return false; } @Override Path relativize(AbstractPath other) { if (other.isAbsolute()) { // only support relativization against relative paths throw new IllegalArgumentException("can only relativize a relative path against a relative path"); } if (other instanceof ElementPath) { // normal case ElementPath otherPath = (ElementPath) other; if (otherPath.startsWith(this)) { if (otherPath.getNameCount() == 1) { return this.getMemoryFileSystem().getEmptyPath(); } else { return other.subpath(1, otherPath.getNameCount()); } } else { List<String> newNameElement = CompositeList.create(Collections.singletonList(".."), otherPath.getNameElements()); return AbstractPath.createRelative(this.getMemoryFileSystem(), newNameElement); } } else { // unknown case throw new IllegalArgumentException("unsupported path argument"); } } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof SingletonPath)) { return false; } SingletonPath other = (SingletonPath) obj; // compareTo take memory file system key into account to ensure // a.compareTo(b) == 0 iff a.equals(b) MemoryFileSystem memoryFileSystem = this.getMemoryFileSystem(); return memoryFileSystem.equals(other.getMemoryFileSystem()) && memoryFileSystem.getCollator().equals(this.fileName, other.fileName); } @Override public int hashCode() { MemoryFileSystem memoryFileSystem = this.getMemoryFileSystem(); Collator collator = memoryFileSystem.getCollator(); // TODO expensive, safe CollationKey collationKey = collator.getCollationKey(this.fileName); int result = 17; result = 31 * result + memoryFileSystem.hashCode(); result = 31 * result + Arrays.hashCode(collationKey.toByteArray()); return result; } @Override public String toString() { return this.fileName; } }