In progress: [ Issue 40 ] Add support for import resolution across multiple folders
https://code.google.com/p/protobuf-dt/issues/detail?id=40
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java
new file mode 100644
index 0000000..73a3305
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.scoping;
+
+import static org.eclipse.emf.common.util.URI.createURI;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.eclipse.protobuf.scoping.IFileUriResolver;
+import com.google.inject.*;
+
+/**
+ * Tests for <code>{@link FileUriResolver#resolveUri(String, Resource)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class FileUriResolver_resolveUri_Test {
+
+  @Rule public XtextRule xtext = new XtextRule();
+  
+  private URI resourceUri;
+  private ResourcesStub resources;
+  private FileUriResolver resolver;
+
+  @Before public void setUp() {
+    resources = new ResourcesStub();
+    resources.resourceShouldAlwaysExist = true;
+    Module module = new Module() {
+      public void configure(Binder binder) {
+        binder.bind(Resources.class).toInstance(resources);
+        binder.bind(IFileUriResolver.class).to(FileUriResolver.class);
+      }
+    };
+    Injector injector = xtext.injector().createChildInjector(module);
+    resourceUri = createURI("platform:/resource/src/proto/person.proto");
+    resolver = (FileUriResolver) injector.getInstance(IFileUriResolver.class);
+  }
+
+  @Test public void should_resolve_import_URI_if_missing_scheme() {
+    resolver.resolveUri("folder1/address.proto", null);
+//    String uri = resolver.resolveUri("folder1/address.proto", resourceUri);
+//    assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
+  }
+//
+//  @Test public void should_not_resolve_import_URI_if_not_missing_scheme() {
+//    String originalUri = "platform:/resource/src/proto/folder1/address.proto";
+//    String uri = resolver.resolveUri(originalUri, resourceUri, resources);
+//    assertThat(uri, equalTo(originalUri));
+//  }
+//  
+//  @Test public void should_resolve_import_URI_even_if_overlapping_folders_with_resource_URI() {
+//    String uri = resolver.resolveUri("src/proto/folder1/address.proto", resourceUri);
+//    assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
+//  }
+//
+//  @Test public void should_resolve_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() {
+//    String uri = resolver.resolveUri("src/proto/read-only/address.proto", resourceUri);
+//    assertThat(uri, equalTo("platform:/resource/src/proto/read-only/address.proto"));  
+//  }
+//  
+  private static class ResourcesStub extends Resources {
+    boolean resourceShouldAlwaysExist;
+    
+    @Override public boolean fileExists(URI uri) {
+      return resourceShouldAlwaysExist;
+    }
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java
deleted file mode 100644
index 4cf9927..0000000
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer_fixUri_Test.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.ui.scoping;
-
-import static org.eclipse.emf.common.util.URI.createURI;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import org.eclipse.emf.common.util.URI;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.eclipse.protobuf.scoping.ResourceChecker;
-
-/**
- * Tests for <code>{@link ProtobufImportUriFixer#fixUri(String, URI, ResourceChecker)}</code>.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class ProtobufImportUriFixer_fixUri_Test {
-
-  private URI resourceUri;
-  private ResourceCheckerStub resourceChecker;
-  private ProtobufImportUriFixer fixer;
-
-  @Before public void setUp() {
-    resourceUri = createURI("platform:/resource/src/proto/person.proto");
-    resourceChecker = new ResourceCheckerStub();
-    resourceChecker.resourceShouldAlwaysExist = true;
-    fixer = new ProtobufImportUriFixer();
-  }
-
-  @Test public void should_fix_import_URI_if_missing_scheme() {
-    String uri = fixer.fixUri("folder1/address.proto", resourceUri, resourceChecker);
-    assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
-  }
-
-  @Test public void should_not_fix_import_URI_if_not_missing_scheme() {
-    String originalUri = "platform:/resource/src/proto/folder1/address.proto";
-    String uri = fixer.fixUri(originalUri, resourceUri, resourceChecker);
-    assertThat(uri, equalTo(originalUri));
-  }
-  
-  @Test public void should_fix_import_URI_even_if_overlapping_folders_with_resource_URI() {
-    String uri = fixer.fixUri("src/proto/folder1/address.proto", resourceUri, resourceChecker);
-    assertThat(uri, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
-  }
-
-  @Test public void should_fix_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() {
-    String uri = fixer.fixUri("src/proto/read-only/address.proto", resourceUri, resourceChecker);
-    assertThat(uri, equalTo("platform:/resource/src/proto/read-only/address.proto"));  
-  }
-  
-  private static class ResourceCheckerStub extends ResourceChecker {
-    boolean resourceShouldAlwaysExist;
-    
-    ResourceCheckerStub() {
-      super(null);
-    }
-
-    @Override public boolean resourceExists(String uri) {
-      return resourceShouldAlwaysExist;
-    }
-  }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
index 322cdcc..5396011 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -16,13 +16,13 @@
 import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution;
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
 
-import com.google.eclipse.protobuf.scoping.ImportUriFixer;
+import com.google.eclipse.protobuf.scoping.IFileUriResolver;
 import com.google.eclipse.protobuf.ui.builder.AutoAddNatureEditorCallback;
 import com.google.eclipse.protobuf.ui.outline.LinkWithEditor;
 import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage;
 import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencesInitializer;
 import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferencesInitializer;
-import com.google.eclipse.protobuf.ui.scoping.ProtobufImportUriFixer;
+import com.google.eclipse.protobuf.ui.scoping.FileUriResolver;
 import com.google.inject.Binder;
 
 /**
@@ -64,7 +64,7 @@
     binder.bind(IPreferenceStoreInitializer.class).annotatedWith(named(name)).to(initializerType);
   }
   
-  public void configureImportUriResolver(Binder binder) {
-    binder.bind(ImportUriFixer.class).to(ProtobufImportUriFixer.class);
+  public void configureFileUriResolver(Binder binder) {
+    binder.bind(IFileUriResolver.class).to(FileUriResolver.class);
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
similarity index 73%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
index c0692f0..5249e26 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/ProtobufImportUriFixer.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
@@ -15,26 +15,24 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
 import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
 import org.eclipse.xtext.util.Pair;
 
-import com.google.eclipse.protobuf.scoping.ImportUriFixer;
-import com.google.eclipse.protobuf.scoping.ResourceChecker;
+import com.google.eclipse.protobuf.scoping.IFileUriResolver;
 import com.google.eclipse.protobuf.ui.preferences.paths.Preferences;
 import com.google.inject.Inject;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ProtobufImportUriFixer implements ImportUriFixer {
+public class FileUriResolver implements IFileUriResolver {
   
   private static final String SEPARATOR = "/";
 
   @Inject private IPreferenceStoreAccess access;
+  @Inject private Resources resources;
   
   /*
    * The import URI is relative to the file where the import is. Protoc works fine, but the editor doesn't.
@@ -51,32 +49,26 @@
    * If we import "folder/proto2.proto" into proto1.proto, proto1.proto will compile fine, but the editor will complain.
    * We need to have the import URI as "platform:/resource/protobuf-test/folder/proto2.proto" for the editor to see it.
    */
-  public String fixUri(String importUri, URI resourceUri, ResourceChecker checker) {
+  public String resolveUri(String importUri, Resource declaringResource) {
     if (importUri.startsWith(PREFIX)) return importUri;
     Pair<String, List<String>> importUriPair = pair(importUri, createURI(importUri).segmentsList());
-    Preferences preferences = Preferences.loadPreferences(access, projectFrom(resourceUri));
-    String fixed = fixUri(importUriPair, resourceUri, checker, preferences);
+    URI resourceUri = declaringResource.getURI();
+    Preferences preferences = Preferences.loadPreferences(access, resources.project(resourceUri));
+    String fixed = fixUri(importUriPair, resourceUri, preferences);
     System.out.println(resourceUri + " : " + importUri + " : " + fixed);
     if (fixed == null) return importUri;
     return fixed;
   }
-
-  private static IProject projectFrom(URI resourceUri) {
-    IPath resourcePath = new Path(resourceUri.toPlatformString(true));
-    IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(resourcePath);
-    return resource.getProject();
-  }
   
-  private String fixUri(Pair<String, List<String>> importUri, URI resourceUri, ResourceChecker checker,
-      Preferences preferences) {
+  private String fixUri(Pair<String, List<String>> importUri, URI resourceUri, Preferences preferences) {
     List<String> segments = removeFirstAndLast(resourceUri.segmentsList());
     if (preferences.fileResolutionType.equals(SINGLE_FOLDER)) {
-      return fixUri(importUri, segments, checker);
+      return fixUri(importUri, segments);
     }
     List<String> folderNames = preferences.folderNames;
     for (String folderName : folderNames) {
       segments.set(1, folderName);
-      String fixed = fixUri(importUri, segments, checker);
+      String fixed = fixUri(importUri, segments);
       if (fixed != null) return fixed;
     }
     return null;
@@ -90,17 +82,17 @@
     return newList;
   }
   
-  private String fixUri(Pair<String, List<String>> importUri, List<String> resourceUri, ResourceChecker checker) {
+  private String fixUri(Pair<String, List<String>> importUri, List<String> resourceUri) {
     StringBuilder prefix = new StringBuilder();
-    prefix.append(PREFIX);
+    // prefix.append(PREFIX);
     String firstSegment = importUri.getSecond().get(0);
     for (String segment : resourceUri) {
       if (segment.equals(firstSegment)) break;
       prefix.append(SEPARATOR).append(segment);
     }
     prefix.append(SEPARATOR);
-    String fixed =  prefix.toString() + importUri.getFirst();
-    if (checker.resourceExists(fixed)) return fixed;
+    String fixed = PREFIX + prefix.toString() + importUri.getFirst();
+    if (resources.fileExists(createURI(fixed))) return fixed;
     return null;
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java
new file mode 100644
index 0000000..b252395
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/Resources.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.scoping;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+
+/**
+ * Utility methods related to resources (e.g. files, directories.)
+ *  
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class Resources {
+
+  /**
+   * Returns the project that contains the resource at the given URI.
+   * @param fileUri the URI of a resource.
+   * @return the project that contains the resource at the given URI.
+   */
+  public IProject project(URI fileUri) {
+    return file(fileUri).getProject();
+  }
+  
+  /**
+   * Indicates whether the given URI belongs to an existing file.
+   * @param fileUri the URI to check, as a {@code String}.
+   * @return {@code true} if the given URI belongs to an existing file, {@code false} otherwise.
+   */
+  public boolean fileExists(URI fileUri) {
+    return file(fileUri).exists();
+  }
+
+  private IFile file(URI uri) {
+    IPath resourcePath = new Path(uri.toPlatformString(true));
+    IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+    return root.getFile(resourcePath);
+  }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java
new file mode 100644
index 0000000..044a1a2
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/IFileUriResolver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.scoping;
+
+import org.eclipse.emf.ecore.resource.Resource;
+
+import com.google.eclipse.protobuf.scoping.IFileUriResolver.NullFileUriResolver;
+import com.google.inject.ImplementedBy;
+
+/**
+ * Resolves partial URIs converting them to full ones belonging to existing files.
+ * 
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@ImplementedBy(NullFileUriResolver.class)
+public interface IFileUriResolver {
+
+  /** Prefix present in resolved URIs. */
+  String PREFIX = "platform:/resource";
+  
+  /**
+   * Resolves the given partial URI.
+   * @param importUri the partial URI (comes from a {@code Import}.)
+   * @param declaringResource the resource declaring the import.
+   * @return the resolved URI.
+   */
+  String resolveUri(String importUri, Resource declaringResource);
+  
+  public static class NullFileUriResolver implements IFileUriResolver {
+    
+    public String resolveUri(String importUri, Resource declaringResource) {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java
deleted file mode 100644
index 5337acd..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ImportUriFixer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.scoping;
-
-import org.eclipse.emf.common.util.URI;
-
-import com.google.eclipse.protobuf.protobuf.Import;
-
-/**
- * Fixes partial URIs in <code>{@link Import}</code>s by resolving them to existing files with matching URIs.
- * 
- * @author alruiz@google.com (Alex Ruiz)
- */
-public interface ImportUriFixer {
-
-  /**
-   * Prefix present in complete import URIs.
-   */
-  String PREFIX = "platform:/resource";
-  
-  /**
-   * Returns a "fixed" full URI based on the given partial URI.
-   * @param importUri the partial URI (comes from a {@code Import}.)
-   * @param resourceUri the URI of the resource declaring the import.
-   * @param checker indicates whether the resolved URI belongs to an existing file.
-   * @return the "fixed" full URI.
-   */
-  String fixUri(String importUri, URI resourceUri, ResourceChecker checker);
-}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java
index 4f4f764..3be0863 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufImportUriResolver.java
@@ -8,7 +8,7 @@
  */
 package com.google.eclipse.protobuf.scoping;
 
-import static com.google.eclipse.protobuf.scoping.ImportUriFixer.PREFIX;
+import static com.google.eclipse.protobuf.scoping.IFileUriResolver.PREFIX;
 
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
@@ -18,7 +18,7 @@
 import com.google.inject.Inject;
 
 /**
- * Resolves URIs. This implementation mimics how protoc understands imported file URIs. For example, the URI
+ * This implementation mimics how protoc understands URIs of imported files. For example, the URI
  * "platform:/resource/proto1.proto" is understood by EMF but not by protoc. The URI in the proto file needs to be
  * simply "proto1.proto" for protoc to understand it.
  * <p>
@@ -30,7 +30,7 @@
  */
 public class ProtobufImportUriResolver extends ImportUriResolver {
 
-  @Inject private ImportUriFixer uriFixer;
+  @Inject private IFileUriResolver delegate;
   
   /**
    * Prefix used by EMF for resource URIs: "platform:/resource/".
@@ -50,8 +50,7 @@
 
   private void fixUri(Import anImport) {
     Resource resource = anImport.eResource();
-    ResourceChecker resourceChecker = new ResourceChecker(resource.getResourceSet());
-    String fixed = uriFixer.fixUri(anImport.getImportURI(), resource.getURI(), resourceChecker);
+    String fixed = delegate.resolveUri(anImport.getImportURI(), resource);
     anImport.setImportURI(fixed);
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java
deleted file mode 100644
index 5231cd3..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ResourceChecker.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.scoping;
-
-import static org.eclipse.emf.common.util.URI.createURI;
-
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-
-/**
- * Verifies that resources exist.
- *  
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class ResourceChecker {
-
-  private final ResourceSet resourceSet;
-
-  public ResourceChecker(ResourceSet resourceSet) {
-    this.resourceSet = resourceSet;
-  }
-  
-  /**
-   * Indicates whether the given URI belongs to an existing resource.
-   * @param uri the URI to check, as a {@code String}.
-   * @return {@code true} if the given URI belongs to an existing resource, {@code false} otherwise.
-   */
-  public boolean resourceExists(String uri) {
-    Resource resource = resourceSet.getResource(createURI(uri), true);
-    return resource != null && resource.getErrors().isEmpty();
-  }
-}