package com.jakewharton.resourcefs;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryStream;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.spi.FileSystemProvider;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

public final class ResourceFileSystemProvider extends FileSystemProvider {
  static final String SCHEME = "resource";

  private final FileSystem fileSystem = new ResourceFileSystem(this);
  private final BasicFileAttributes fileAttributes = new ResourceFileAttributes();
  final FileStore fileStore = new ResourceFileStore();

  @Override public String getScheme() {
    return SCHEME;
  }

  @Override public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
    return fileSystem;
  }

  @Override public FileSystem getFileSystem(URI uri) {
    return fileSystem;
  }

  @Override public Path getPath(URI uri) {
    if (!uri.getScheme().equalsIgnoreCase(SCHEME)) {
      throw new IllegalArgumentException("Scheme mismatch: " + uri.toString());
    }
    return new ResourcePath(fileSystem, uri);
  }

  @Override public InputStream newInputStream(Path path, OpenOption... options) throws IOException {
    if (!path.isAbsolute()) {
      throw new IllegalArgumentException("Only absolute paths allowed: " + path.toUri().toString());
    }
    InputStream is = getClass().getResourceAsStream(path.toUri().toString());
    if (is == null) {
      throw new FileNotFoundException(path.toUri().toString());
    }
    return is;
  }

  @Override public FileSystem newFileSystem(Path path, Map<String, ?> env) throws IOException {
    return fileSystem;
  }

  @Override public OutputStream newOutputStream(Path path, OpenOption... options)
      throws IOException {
    throw readOnly();
  }

  @Override public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options,
      FileAttribute<?>... attrs) throws IOException {
    throw new UnsupportedOperationException(); // TODO
  }

  @Override
  public SeekableByteChannel newByteChannel(final Path path, Set<? extends OpenOption> options,
      FileAttribute<?>... attrs) throws IOException {
    try (InputStream is = newInputStream(path)) {
      byte[] bytes = Streams.toByteArray(is);
      return new SeekableByteArrayChannel(bytes);
    }
  }

  @Override public DirectoryStream<Path> newDirectoryStream(Path dir,
      DirectoryStream.Filter<? super Path> filter) throws IOException {
    throw new UnsupportedOperationException(); // TODO
  }

  @Override public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
    throw readOnly();
  }

  @Override public void delete(Path path) throws IOException {
    throw readOnly();
  }

  @Override public void copy(Path source, Path target, CopyOption... options) throws IOException {
    throw readOnly();
  }

  @Override public void move(Path source, Path target, CopyOption... options) throws IOException {
    throw readOnly();
  }

  @Override public boolean isSameFile(Path path, Path path2) throws IOException {
    return path.equals(path2);
  }

  @Override public boolean isHidden(Path path) throws IOException {
    return false;
  }

  @Override public FileStore getFileStore(Path path) throws IOException {
    return fileStore;
  }

  @Override public void checkAccess(Path path, AccessMode... modes) throws IOException {
    throw new UnsupportedOperationException(); // TODO
  }

  @Override public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type,
      LinkOption... options) {
    throw new UnsupportedOperationException(); // TODO
  }

  @Override public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type,
      LinkOption... options) throws IOException {
    if (type != BasicFileAttributes.class) {
      throw new IllegalArgumentException("Unsupported attributes: " + type.getCanonicalName());
    }
    return type.cast(fileAttributes);
  }

  @Override
  public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options)
      throws IOException {
    return Collections.emptyMap(); // TODO
  }

  @Override
  public void setAttribute(Path path, String attribute, Object value, LinkOption... options)
      throws IOException {
    throw readOnly();
  }

  private static IOException readOnly() throws IOException {
    throw new UnsupportedOperationException("Resources are read only.");
  }
}

@@ -250,32 +250,76 @@
 bleByteChannel;%0A
+import java.nio.file.AccessDeniedException;%0A
 import java.nio.
@@ -335,16 +335,16 @@
 ssMode;%0A
-
 import j
@@ -1160,16 +1160,364 @@
 ore();%0A%0A
+  private void checkExists(Path path) throws FileNotFoundException %7B%0A    if (!path.isAbsolute()) %7B%0A      throw new IllegalArgumentException(%22Only absolute paths allowed: %22 + path.toUri().toString());%0A    %7D%0A    if (getClass().getResource(path.toUri().toString()) == null) %7B%0A      throw new FileNotFoundException(path.toUri().toString());%0A    %7D%0A  %7D%0A%0A
   @Overr
@@ -2119,324 +2119,93 @@
     
-if (!path.isAbsolute()) %7B%0A      throw new IllegalArgumentException(%22Only absolute paths allowed: %22 + path.toUri().toString());%0A    %7D%0A    InputStream is = getClass().getResourceAsStream(path.toUri().toString());%0A    if (is == null) %7B%0A      throw new FileNotFoundException(path.toUri().toString());%0A    %7D%0A    return is
+checkExists(path);%0A    return getClass().getResourceAsStream(path.toUri().toString())
 ;%0A  
@@ -3839,32 +3839,55 @@
 s IOException %7B%0A
+    checkExists(path);%0A
     return false
@@ -3959,32 +3959,55 @@
 s IOException %7B%0A
+    checkExists(path);%0A
     return fileS
@@ -4114,58 +4114,261 @@
     
-throw new UnsupportedOperationException(); // TODO
+checkExists(path);%0A    for (AccessMode mode : modes) %7B%0A      if (mode == AccessMode.WRITE) %7B%0A        throw readOnly();%0A      %7D else if (mode == AccessMode.EXECUTE) %7B%0A        throw new AccessDeniedException(%22Resources are not executable.%22);%0A      %7D%0A    %7D
 %0A  %7D
@@ -4841,32 +4841,55 @@
 lName());%0A    %7D%0A
+    checkExists(path);%0A
     return type.
@@ -5016,32 +5016,32 @@
 ion... options)%0A
-
       throws IOE
@@ -5043,32 +5043,55 @@
 s IOException %7B%0A
+    checkExists(path);%0A
     return Colle

Implement checkAccess and added existence checks to all methods.