In progress: [ Issue 40 ] Add support for import resolution across multiple folders
https://code.google.com/p/protobuf-dt/issues/detail?id=40

Code cleanup.
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
index 7cba64e..9a41d2e 100644
--- 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
@@ -8,7 +8,7 @@
  */
 package com.google.eclipse.protobuf.ui.scoping;
 
-import static com.google.eclipse.protobuf.ui.preferences.paths.FileResolutionType.SINGLE_FOLDER;
+import static com.google.eclipse.protobuf.ui.preferences.paths.PathResolutionType.SINGLE_DIRECTORY;
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Matchers.any;
@@ -35,8 +35,8 @@
   @Rule public XtextRule xtext = new XtextRule();
   
   private Resource resource;
-  private PreferenceReader preferenceReader;
-  private Preferences preferences;
+  private PathsPreferenceReader preferenceReader;
+  private PathsPreferences preferences;
   private IProject project;
   private Resources resources;
 
@@ -44,13 +44,13 @@
 
   @Before public void setUp() {
     resource = new ResourceStub("platform:/resource/src/proto/person.proto");
-    preferenceReader = mock(PreferenceReader.class);
-    preferences = mock(Preferences.class);
+    preferenceReader = mock(PathsPreferenceReader.class);
+    preferences = mock(PathsPreferences.class);
     project = mock(IProject.class);
     resources = mock(Resources.class);
     Module module = new Module() {
       public void configure(Binder binder) {
-        binder.bind(PreferenceReader.class).toInstance(preferenceReader);
+        binder.bind(PathsPreferenceReader.class).toInstance(preferenceReader);
         binder.bind(Resources.class).toInstance(resources);
         binder.bind(IFileUriResolver.class).to(FileUriResolver.class);
       }
@@ -60,34 +60,34 @@
   }
 
   @Test public void should_resolve_import_URI_if_missing_scheme() {
-    callStubs(SINGLE_FOLDER, true);
+    callStubs(SINGLE_DIRECTORY, true);
     String resolved = resolver.resolveUri("folder1/address.proto", resource);
     assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
   }
   
   @Test public void should_not_resolve_import_URI_if_not_missing_scheme() {
-    callStubs(SINGLE_FOLDER, true);
+    callStubs(SINGLE_DIRECTORY, true);
     String original = "platform:/resource/src/proto/folder1/address.proto";
     String resolved = resolver.resolveUri(original, resource);
     assertThat(resolved, equalTo(original));
   }
   
   @Test public void should_resolve_import_URI_even_if_overlapping_folders_with_resource_URI() {
-    callStubs(SINGLE_FOLDER, true);
+    callStubs(SINGLE_DIRECTORY, true);
     String resolved = resolver.resolveUri("src/proto/folder1/address.proto", resource);
     assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto"));  
   }
 
   @Test public void should_resolve_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() {
-    callStubs(SINGLE_FOLDER, true);
+    callStubs(SINGLE_DIRECTORY, true);
     String resolved = resolver.resolveUri("src/proto/read-only/address.proto", resource);
     assertThat(resolved, equalTo("platform:/resource/src/proto/read-only/address.proto"));  
   }
 
-  private void callStubs(FileResolutionType type, boolean resolvedUriExists) {
+  private void callStubs(PathResolutionType type, boolean resolvedUriExists) {
     when(resources.project(resource.getURI())).thenReturn(project);
     when(preferenceReader.readFromPrefereceStore(project)).thenReturn(preferences);
-    when(preferences.fileResolutionType()).thenReturn(type);
+    when(preferences.pathResolutionType()).thenReturn(type);
     when(resources.fileExists(any(URI.class))).thenReturn(resolvedUriExists);
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferences.java
index 77142c2..98e5be5 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferences.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferences.java
@@ -39,9 +39,9 @@
     compileProtoFiles = store.getBoolean(COMPILE_PROTO_FILES);
     boolean useProtocInSystemPath = store.getBoolean(USE_PROTOC_IN_SYSTEM_PATH);
     protocPath = (useProtocInSystemPath) ? "protoc" : store.getString(PROTOC_FILE_PATH);
-    language = CompilerTargetLanguage.find(store);
+    language = CompilerTargetLanguage.readFrom(store);
     outputFolderName = store.getString(OUTPUT_FOLDER_NAME);
     refreshResources = store.getBoolean(REFRESH_RESOURCES);
-    refreshTarget = PostCompilationRefreshTarget.find(store);
+    refreshTarget = PostCompilationRefreshTarget.readFrom(store);
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerTargetLanguage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerTargetLanguage.java
index 9bf1185..820596b 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerTargetLanguage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerTargetLanguage.java
@@ -22,7 +22,7 @@
   JAVA, CPP, PYTHON;
 
   // TODO check if protoc can generate more than one language sources at the same time.
-  static CompilerTargetLanguage find(IPreferenceStore store) {
+  static CompilerTargetLanguage readFrom(IPreferenceStore store) {
     if (store.getBoolean(GENERATE_JAVA_CODE)) return JAVA;
     if (store.getBoolean(GENERATE_CPP_CODE)) return CPP;
     if (store.getBoolean(GENERATE_PYTHON_CODE)) return PYTHON;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PostCompilationRefreshTarget.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PostCompilationRefreshTarget.java
index cfba624..1a73ce0 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PostCompilationRefreshTarget.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PostCompilationRefreshTarget.java
@@ -21,7 +21,7 @@
 
   PROJECT, OUTPUT_FOLDER;
 
-  static PostCompilationRefreshTarget find(IPreferenceStore store) {
+  static PostCompilationRefreshTarget readFrom(IPreferenceStore store) {
     if (store.getBoolean(REFRESH_PROJECT)) return PROJECT;
     return OUTPUT_FOLDER;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsResolutionType.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathResolutionType.java
similarity index 88%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsResolutionType.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathResolutionType.java
index c24670a..c54904c 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsResolutionType.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathResolutionType.java
@@ -16,11 +16,11 @@
  * 
  * @author alruiz@google.com (Alex Ruiz)
  */
-public enum PathsResolutionType {
+public enum PathResolutionType {
 
   SINGLE_DIRECTORY, MULTIPLE_DIRECTORIES;
   
-  static PathsResolutionType find(IPreferenceStore store) {
+  static PathResolutionType readFrom(IPreferenceStore store) {
     if (store.getBoolean(FILES_IN_ONE_DIRECTORY_ONLY)) return SINGLE_DIRECTORY;
     return MULTIPLE_DIRECTORIES;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferences.java
index 5f6fa68..97f7ccd 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferences.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferences.java
@@ -8,8 +8,8 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.paths;
 
-import static com.google.eclipse.protobuf.ui.preferences.paths.PathsResolutionType.SINGLE_DIRECTORY;
 import static com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferenceNames.DIRECTORY_NAMES;
+import static com.google.eclipse.protobuf.ui.preferences.paths.PathResolutionType.SINGLE_DIRECTORY;
 import static com.google.eclipse.protobuf.ui.util.Strings.CSV_PATTERN;
 import static java.util.Arrays.asList;
 import static java.util.Collections.*;
@@ -20,30 +20,30 @@
 
 /**
  * Paths preferences, retrieved from an <code>{@link IPreferenceStore}</code>.
- * 
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class PathsPreferences {
 
-  private final PathsResolutionType fileResolutionType;
-  private final List<String> folderNames; 
-  
+  private final PathResolutionType pathResolutionType;
+  private final List<String> directoryNames;
+
   PathsPreferences(IPreferenceStore store) {
-    fileResolutionType = PathsResolutionType.find(store);
-    folderNames = folderNames(fileResolutionType, store);
+    pathResolutionType = PathResolutionType.readFrom(store);
+    directoryNames = directoryNames(pathResolutionType, store);
   }
-  
-  private static List<String> folderNames(PathsResolutionType types, IPreferenceStore store) {
+
+  private static List<String> directoryNames(PathResolutionType types, IPreferenceStore store) {
     if (types.equals(SINGLE_DIRECTORY)) return emptyList();
-    String[] folderNames = store.getString(DIRECTORY_NAMES).split(CSV_PATTERN);
-    return unmodifiableList(asList(folderNames));
+    String[] directoryNames = store.getString(DIRECTORY_NAMES).split(CSV_PATTERN);
+    return unmodifiableList(asList(directoryNames));
   }
 
-  public PathsResolutionType fileResolutionType() {
-    return fileResolutionType;
+  public PathResolutionType pathResolutionType() {
+    return pathResolutionType;
   }
 
-  public List<String> folderNames() {
-    return folderNames;
+  public List<String> directoryNames() {
+    return directoryNames;
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategies.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategies.java
new file mode 100644
index 0000000..ee257a2
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategies.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.google.eclipse.protobuf.ui.preferences.paths.PathResolutionType.*;
+import static com.google.inject.internal.Maps.newHashMap;
+
+import java.util.Map;
+
+import com.google.eclipse.protobuf.ui.preferences.paths.PathResolutionType;
+import com.google.inject.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+class FileResolverStrategies {
+
+  private final Map<PathResolutionType, FileResolverStrategy> strategies = newHashMap();
+
+  @Inject FileResolverStrategies(Resources resources) {
+    strategies.put(SINGLE_DIRECTORY, new SingleDirectoryFileResolver(resources));
+    strategies.put(MULTIPLE_DIRECTORIES, new MultipleDirectoriesFileResolver());
+  }
+
+  FileResolverStrategy strategyFor(PathResolutionType type) {
+    return strategies.get(type);
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategy.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategy.java
new file mode 100644
index 0000000..328fadb
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileResolverStrategy.java
@@ -0,0 +1,25 @@
+/*
+ * 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.IProject;
+import org.eclipse.emf.common.util.URI;
+
+import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface FileResolverStrategy {
+
+  String PREFIX = "platform:/resource";
+  String SEPARATOR = "/";
+
+  String resolveUri(String importUri, URI declaringResourceUri, PathsPreferences preferences, IProject project);
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
index 68d26a1..913e46f 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
@@ -8,35 +8,27 @@
  */
 package com.google.eclipse.protobuf.ui.scoping;
 
-import static com.google.eclipse.protobuf.ui.preferences.paths.PathsResolutionType.SINGLE_DIRECTORY;
-import static org.eclipse.emf.common.util.URI.createURI;
-import static org.eclipse.xtext.util.Tuples.pair;
-
-import java.util.ArrayList;
-import java.util.List;
+import static com.google.eclipse.protobuf.ui.scoping.FileResolverStrategy.PREFIX;
 
 import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.xtext.util.Pair;
 
 import com.google.eclipse.protobuf.scoping.IFileUriResolver;
-import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferenceReader;
-import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences;
+import com.google.eclipse.protobuf.ui.preferences.paths.*;
 import com.google.inject.Inject;
 
 /**
+ * Resolves "import" URIs.
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class FileUriResolver implements IFileUriResolver {
-  
-  private static final String PREFIX = "platform:/resource";
-  private static final String SEPARATOR = "/";
 
   @Inject private PathsPreferenceReader preferenceReader;
+  @Inject private FileResolverStrategies resolvers;
   @Inject private Resources resources;
-  
+
   /*
    * The import URI is relative to the file where the import is. Protoc works fine, but the editor doesn't.
    * In order for the editor to see the import, we need to add to the import URI "platform:resource" and the parent
@@ -54,50 +46,19 @@
    */
   public String resolveUri(String importUri, Resource declaringResource) {
     if (importUri.startsWith(PREFIX)) return importUri;
-    Pair<String, List<String>> importUriPair = pair(importUri, createURI(importUri).segmentsList());
-    String resolved = resolveUri(importUriPair, declaringResource.getURI());
+    String resolved = resolveUri(importUri, declaringResource.getURI());
 //    System.out.println(declaringResource.getURI() + " : " + importUri + " : " + resolved);
     if (resolved == null) return importUri;
     return resolved;
   }
-  
-  private String resolveUri(Pair<String, List<String>> importUri, URI resourceUri) {
+
+  private String resolveUri(String importUri, URI resourceUri) {
     IProject project = resources.project(resourceUri);
     PathsPreferences preferences = preferenceReader.readFromPrefereceStore(project);
-    List<String> segments = removeFirstAndLast(resourceUri.segmentsList());
-    if (preferences.fileResolutionType().equals(SINGLE_DIRECTORY)) {
-      return resolveUri(importUri, segments);
-    }
-    for (String folderName : preferences.folderNames()) {
-      String resolved = resolveUri(importUri, folderName, project);
-      if (resolved != null) return resolved;
-    }
-    return null;
+    return resolver(preferences).resolveUri(importUri, resourceUri, preferences, project);
   }
-  
-  private List<String> removeFirstAndLast(List<String> list) {
-    if (list.isEmpty()) return list;
-    List<String> newList = new ArrayList<String>(list);
-    newList.remove(0);
-    newList.remove(newList.size() - 1);
-    return newList;
-  }
-  
-  private String resolveUri(Pair<String, List<String>> importUri, List<String> resourceUri) {
-    StringBuilder pathBuilder = new StringBuilder();
-    String firstSegment = importUri.getSecond().get(0);
-    for (String segment : resourceUri) {
-      if (segment.equals(firstSegment)) break;
-      pathBuilder.append(segment).append(SEPARATOR);
-    }
-    String resolved = PREFIX + SEPARATOR + pathBuilder.toString() + importUri.getFirst();
-    return (resources.fileExists(createURI(resolved))) ? resolved : null;
-  }
-  
-  private String resolveUri(Pair<String, List<String>> importUri, String folderName, IProject project) {
-    String path = folderName + SEPARATOR + importUri.getFirst();
-    IResource findMember = project.findMember(path);
-    boolean exists = (findMember != null) ? findMember.exists() : false;
-    return (exists) ? PREFIX +  project.getFullPath() + SEPARATOR + path : null;
+
+  private FileResolverStrategy resolver(PathsPreferences preferences) {
+    return resolvers.strategyFor(preferences.pathResolutionType());
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/MultipleDirectoriesFileResolver.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/MultipleDirectoriesFileResolver.java
new file mode 100644
index 0000000..a96766c
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/MultipleDirectoriesFileResolver.java
@@ -0,0 +1,36 @@
+/*
+ * 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.emf.common.util.URI;
+
+import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class MultipleDirectoriesFileResolver implements FileResolverStrategy {
+
+  /** {@inheritDoc} */
+  public String resolveUri(String importUri, URI declaringResourceUri, PathsPreferences preferences, IProject project) {
+    for (String directoryName : preferences.directoryNames()) {
+      String resolved = resolveUri(importUri, directoryName, project);
+      if (resolved != null) return resolved;
+    }
+    return null;
+  }
+
+  private String resolveUri(String importUri, String directoryName, IProject project) {
+    String path = directoryName + SEPARATOR + importUri;
+    IResource findMember = project.findMember(path);
+    boolean exists = (findMember != null) ? findMember.exists() : false;
+    return (exists) ? PREFIX +  project.getFullPath() + SEPARATOR + path : 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
index 2839af5..dbda15e 100644
--- 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
@@ -9,15 +9,17 @@
 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.core.runtime.*;
 import org.eclipse.emf.common.util.URI;
 
+import com.google.inject.Singleton;
+
 /**
  * Utility methods related to resources (e.g. files, directories.)
- *  
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
+@Singleton
 public class Resources {
 
   /**
@@ -28,7 +30,7 @@
   public IProject project(URI resourceUri) {
     return file(resourceUri).getProject();
   }
-  
+
   /**
    * Indicates whether the given URI belongs to an existing file.
    * @param fileUri the URI to check, as a {@code String}.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver.java
new file mode 100644
index 0000000..bcee62c
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver.java
@@ -0,0 +1,59 @@
+/*
+ * 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.eclipse.xtext.util.Tuples.pair;
+
+import java.util.*;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.util.Pair;
+
+import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class SingleDirectoryFileResolver implements FileResolverStrategy {
+
+  private final Resources resources;
+
+  SingleDirectoryFileResolver(Resources resources) {
+    this.resources = resources;
+  }
+
+  public String resolveUri(String importUri, URI declaringResourceUri, PathsPreferences preferences, IProject project) {
+    List<String> resourceUriSegments = removeFirstAndLast(declaringResourceUri.segmentsList());
+    Pair<String, List<String>> importUriPair = pair(importUri, createURI(importUri).segmentsList());
+    return resolveUri(importUriPair, resourceUriSegments);
+  }
+
+  // first is always "platform" and last is the file name (both unnecessary)
+  private static List<String> removeFirstAndLast(List<String> list) {
+    if (list.isEmpty()) return list;
+    List<String> newList = new ArrayList<String>(list);
+    newList.remove(0);
+    newList.remove(newList.size() - 1);
+    return newList;
+  }
+
+  private String resolveUri(Pair<String, List<String>> importUri, List<String> resourceUri) {
+    StringBuilder pathBuilder = new StringBuilder();
+    String firstSegment = importUri.getSecond().get(0);
+    for (String segment : resourceUri) {
+      if (segment.equals(firstSegment)) break;
+      pathBuilder.append(segment).append(SEPARATOR);
+    }
+    String resolved = PREFIX + SEPARATOR + pathBuilder.toString() + importUri.getFirst();
+    return (resources.fileExists(createURI(resolved))) ? resolved : null;
+  }
+
+}
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
index 58257de..ecc39cd 100644
--- 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
@@ -14,21 +14,21 @@
 import com.google.inject.ImplementedBy;
 
 /**
- * Resolves partial URIs converting them to full ones belonging to existing files.
- * 
+ * Resolves "import" URIs.
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
 @ImplementedBy(NullFileUriResolver.class)
 public interface IFileUriResolver {
 
   /**
-   * Resolves the given partial URI.
-   * @param importUri the partial URI (comes from a {@code Import}.)
+   * Resolves the given 'import' URI.
+   * @param importUri the 'import' URI.
    * @param declaringResource the resource declaring the import.
-   * @return the resolved URI.
+   * @return the resolved URI, or {@code importUri} if resolution was not successful.
    */
   String resolveUri(String importUri, Resource declaringResource);
-  
+
   class NullFileUriResolver implements IFileUriResolver {
     public String resolveUri(String importUri, Resource declaringResource) {
       throw new UnsupportedOperationException();