// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.application.options;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier;
import com.intellij.psi.codeStyle.modifier.TransientCodeStyleSettings;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import org.jetbrains.annotations.NotNull;

class CodeStyleCachingUtil {
  private final static Logger LOG = Logger.getInstance(CodeStyleCachingUtil.class);

  private final static ExtensionPointName<CodeStyleSettingsModifier> CODE_STYLE_SETTINGS_MODIFIER_EP_NAME =
    ExtensionPointName.create("com.intellij.codeStyleSettingsModifier");

  @NotNull
  static CodeStyleSettings getCachedCodeStyle(@NotNull PsiFile file) {
    CachedCodeStyleHolder cachedCodeStyleHolder = CachedValuesManager.getCachedValue(
      file,
      () -> {
        CachedCodeStyleHolder holder = new CachedCodeStyleHolder(file);
        if (LOG.isDebugEnabled()) {
          logCached(file, holder);
        }
        return new CachedValueProvider.Result<>(holder, holder.getDependencies());
      });
    return cachedCodeStyleHolder.getCachedSettings();
  }

  static class CachedCodeStyleHolder {
    private @NotNull CodeStyleSettings myCachedSettings;

    CachedCodeStyleHolder(@NotNull PsiFile file) {
      //noinspection deprecation
      myCachedSettings = CodeStyleSettingsManager.getInstance(file.getProject()).getCurrentSettings();
      updateFor(file);
    }

    private void updateFor(@NotNull PsiFile file) {
      TransientCodeStyleSettings modifiableSettings = new TransientCodeStyleSettings(file, myCachedSettings);
      for (CodeStyleSettingsModifier modifier : CODE_STYLE_SETTINGS_MODIFIER_EP_NAME.getExtensionList()) {
        if (modifier.modifySettings(modifiableSettings, file)) {
          LOG.debug("Modifier: " + modifier.getClass().getName());
          modifiableSettings.setModifier(modifier);
          myCachedSettings = modifiableSettings;
          break;
        }
      }
    }

    @NotNull
    Object[] getDependencies() {
      return myCachedSettings instanceof TransientCodeStyleSettings ?
             ((TransientCodeStyleSettings)myCachedSettings).getDependencies().toArray() :
             new Object[]{myCachedSettings.getModificationTracker()};
    }

    @NotNull
    CodeStyleSettings getCachedSettings() {
      return myCachedSettings;
    }
  }

  private static void logCached(@NotNull PsiFile file, @NotNull CachedCodeStyleHolder holder) {
    CodeStyleSettings settings = holder.getCachedSettings();
    LOG.debug(String.format(
      "File: %s (%s), cached: %s, tracker: %d", file.getName(), Integer.toHexString(file.hashCode()), settings, settings.getModificationTracker().getModificationCount()));
  }
}

@@ -825,16 +825,79 @@
 .class);
+%0A  private final static Object COMPUTATION_LOCK = new Object();
 %0A%0A  priv
@@ -1243,99 +1243,317 @@
 lue(
-%0A      file,%0A      () -%3E %7B%0A        CachedCodeStyleHolder holder = new CachedCodeStyleHolder
+file, () -%3E createHolder(file).getCachedResult());%0A    return cachedCodeStyleHolder.getCachedSettings();%0A  %7D%0A%0A  private static CachedCodeStyleHolder createHolder(@NotNull PsiFile file) %7B%0A    CachedCodeStyleHolder holder = new CachedCodeStyleHolder();%0A    synchronized (COMPUTATION_LOCK) %7B%0A      holder.compute
 (fil
@@ -1556,24 +1556,26 @@
 (file);%0A    
+%7D%0A
     if (LOG.
@@ -1600,20 +1600,16 @@
 %7B%0A      
-    
 logCache
@@ -1629,26 +1629,18 @@
 r);%0A    
-   
- 
 %7D%0A
-    
     retu
@@ -1646,138 +1646,14 @@
 urn 
-new CachedValueProvider.Result%3C%3E(holder, holder.getDependencies());%0A      %7D);%0A    return cachedCodeStyleHolder.getCachedSettings()
+holder
 ;%0A  
@@ -1753,36 +1753,68 @@
 ings
-;%0A%0A    CachedCodeStyleHolder
+ = CodeStyle.getDefaultSettings();%0A%0A    private void compute
 (@No
@@ -1975,90 +1975,8 @@
 ();%0A
-      updateFor(file);%0A    %7D%0A%0A    private void updateFor(@NotNull PsiFile file) %7B%0A
     
@@ -2839,16 +2839,174 @@
 s;%0A    %7D
+%0A%0A    CachedValueProvider.Result%3CCachedCodeStyleHolder%3E getCachedResult() %7B%0A      return new CachedValueProvider.Result%3C%3E(this, this.getDependencies());%0A    %7D
 %0A  %7D%0A%0A  

Fix code style caching exception: Non-idempotent computation: it returns different results when invoked multiple times