package org.editorconfig.plugincomponents;

import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootModificationTracker;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SimpleModificationTracker;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.CachedValueImpl;
import org.editorconfig.Utils;
import org.editorconfig.core.EditorConfig;
import org.editorconfig.core.EditorConfig.OutPair;
import org.editorconfig.core.EditorConfigException;

import java.util.*;

public class SettingsProviderComponent extends SimpleModificationTracker {
  private static final Key<CachedValue<List<OutPair>>> CACHED_PAIRS = Key.create("editorconfig.cached.pairs");
  private EditorConfig editorConfig;

  public SettingsProviderComponent() {
    editorConfig = new EditorConfig();
  }

  public static SettingsProviderComponent getInstance() {
    return ServiceManager.getService(SettingsProviderComponent.class);
  }

  public List<OutPair> getOutPairs(Project project, VirtualFile file) {
    CachedValue<List<OutPair>> cache = file.getUserData(CACHED_PAIRS);
    if (cache == null) {
      cache = new CachedValueImpl<>(() -> {
        final String filePath = Utils.getFilePath(project, file);
        if (filePath == null) return CachedValueProvider.Result.create(Collections.emptyList(), this);

        final List<OutPair> outPairs;
        try {
          final Set<String> rootDirs = getRootDirs(project);
          outPairs = editorConfig.getProperties(filePath, rootDirs);
          return CachedValueProvider.Result.create(outPairs, this);
        }
        catch (EditorConfigException error) {
          Utils.invalidConfigMessage(project, error.getMessage(), "", filePath);
          return CachedValueProvider.Result.create(Collections.emptyList(), this);
        }
      });
      file.putUserData(CACHED_PAIRS, cache);
    }
    return cache.getValue();
  }

  public Set<String> getRootDirs(final Project project) {
    if (!Registry.is("editor.config.stop.at.project.root")) {
      return Collections.emptySet();
    }

    return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
      final Set<String> dirs = new HashSet<>();
      final VirtualFile projectBase = project.getBaseDir();
      if (projectBase != null) {
        dirs.add(project.getBasePath());
        for (Module module : ModuleManager.getInstance(project).getModules()) {
          for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) {
            if (!VfsUtilCore.isAncestor(projectBase, root, false)) {
              dirs.add(root.getPath());
            }
          }
        }
      }
      dirs.add(PathManager.getConfigPath());
      return new CachedValueProvider.Result<>(dirs, ProjectRootModificationTracker.getInstance(project));
    });
  }
}

@@ -552,16 +552,66 @@
 gistry;%0A
+import com.intellij.openapi.util.text.StringUtil;%0A
 import c
@@ -1261,16 +1261,68 @@
 airs%22);%0A
+  public static final String ERROR = %22___error___%22;%0A
   privat
@@ -1636,24 +1636,144 @@
 ile file) %7B%0A
+    final String filePath = Utils.getFilePath(project, file);%0A    if (filePath == null) return Collections.emptyList();%0A
     CachedVa
@@ -1860,54 +1860,8 @@
 ) %7B%0A
-      cache = new CachedValueImpl%3C%3E(() -%3E %7B%0A  
     
@@ -1872,51 +1872,50 @@
 nal 
+Set%3C
 String
- filePath = Utils.getFilePath
+%3E rootDirs = getRootDirs
 (project
 , fi
@@ -1906,30 +1906,24 @@
 Dirs(project
-, file
 );%0A        i
@@ -1923,105 +1923,45 @@
     
-  if (filePath == null) return CachedValueProvider.Result.create(Collections.emptyList(), this);%0A
+cache = new CachedValueImpl%3C%3E(() -%3E %7B
 %0A   
@@ -2013,69 +2013,8 @@
 y %7B%0A
-          final Set%3CString%3E rootDirs = getRootDirs(project);%0A
     
@@ -2216,42 +2216,103 @@
     
-Utils.invalidConfigMessage(project
+ArrayList%3COutPair%3E errorResult = new ArrayList%3C%3E();%0A          errorResult.add(new OutPair(ERROR
 , er
@@ -2331,22 +2331,9 @@
 ge()
-, %22%22, filePath
+)
 );%0A 
@@ -2382,39 +2382,27 @@
 .create(
-Collections.emptyList()
+errorResult
 , this);
@@ -2481,31 +2481,233 @@
     
-return cache.getValue()
+List%3COutPair%3E result = cache.getValue();%0A    String error = Utils.configValueForKey(result, ERROR);%0A    if (!StringUtil.isEmpty(error)) %7B%0A      Utils.invalidConfigMessage(project, error, %22%22, filePath);%0A    %7D%0A    return result
 ;%0A  

fix project leak