/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.openapi.editor.colors;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.JBIterable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public final class ColorKey implements Comparable<ColorKey> {
  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.colors.ColorKey");

  private static final ConcurrentMap<String, ColorKey> ourRegistry = new ConcurrentHashMap<>();

  private final String myExternalName;
  private final Color myDefaultColor;
  private final ColorKey myFallbackColorKey;

  private ColorKey(@NotNull String externalName, Color defaultColor, ColorKey fallBackColorKey) {
    myExternalName = externalName;
    myDefaultColor = defaultColor;
    myFallbackColorKey = fallBackColorKey;
  }

  @NotNull
  public static ColorKey find(@NotNull String externalName) {
    return ourRegistry.computeIfAbsent(externalName, s -> new ColorKey(s,null,null));
  }

  @Override
  public String toString() {
    return myExternalName;
  }

  @NotNull
  public String getExternalName() {
    return myExternalName;
  }

  @Override
  public int compareTo(@NotNull ColorKey key) {
    return myExternalName.compareTo(key.myExternalName);
  }

  public Color getDefaultColor() {
    return myDefaultColor;
  }

  @Nullable
  public ColorKey getFallbackColorKey() {
    return myFallbackColorKey;
  }

  @NotNull
  public static ColorKey createColorKey(@NonNls @NotNull String externalName) {
    return find(externalName);
  }

  @NotNull
  public static ColorKey createColorKey(@NonNls @NotNull String externalName, @Nullable ColorKey fallbackColorKey) {
    ColorKey existing = ourRegistry.get(externalName);
    if (existing != null) {
      if (Comparing.equal(existing.getFallbackColorKey(), fallbackColorKey)) return existing;
      // some crazy life cycle assumes we can overwrite color
      ourRegistry.remove(externalName, existing);
    }
    ColorKey newKey = new ColorKey(externalName, existing == null ? null : existing.getDefaultColor(), fallbackColorKey);
    ColorKey res = ConcurrencyUtil.cacheOrGet(ourRegistry, externalName, newKey);

    if (fallbackColorKey != null) {
      JBIterable<ColorKey> it = JBIterable.generate(fallbackColorKey, o -> o == res ? null : o.myFallbackColorKey);
      if (it.find(o -> o == res) == res) {
        String cycle = StringUtil.join(it.map(ColorKey::getExternalName), "->");
        LOG.error("Cycle detected: " + cycle);
      }
    }

    return res;
  }

  @NotNull
  public static ColorKey createColorKey(@NonNls @NotNull String externalName, @Nullable Color defaultColor) {
    ColorKey existing = ourRegistry.get(externalName);
    if (existing != null) {
      if (Comparing.equal(existing.getDefaultColor(), defaultColor)) return existing;
      // some crazy life cycle assumes we should overwrite default color
      // (e.g. when read from external schema HintUtil.INFORMATION_COLOR_KEY with null color, then try to re-create it with not-null color in HintUtil initializer)
      ourRegistry.remove(externalName, existing);
    }
    ColorKey newKey = new ColorKey(externalName, defaultColor, existing == null ? null : existing.getFallbackColorKey());
    return ConcurrencyUtil.cacheOrGet(ourRegistry, externalName, newKey);
  }

  @Override
  public int hashCode() {
    return myExternalName.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    return obj instanceof ColorKey && myExternalName.equals(((ColorKey)obj).myExternalName);
  }
}

@@ -671,209 +671,64 @@
 api.
-diagnostic.Logger;%0Aimport com.intellij.openapi.util.Comparing;%0Aimport com.intellij.openapi.util.text.StringUtil;%0Aimport com.intellij.util.ConcurrencyUtil;%0Aimport com.intellij.util.containers.JBIterable
+util.Comparing;%0Aimport com.intellij.util.ConcurrencyUtil
 ;%0Aim
@@ -1028,113 +1028,8 @@
 %3E %7B%0A
-  private static final Logger LOG = Logger.getInstance(%22#com.intellij.openapi.editor.colors.ColorKey%22);%0A%0A
   pr
@@ -1121,16 +1121,27 @@
 p%3C%3E();%0A%0A
+  @NotNull%0A
   privat
@@ -1212,53 +1212,8 @@
 lor;
-%0A  private final ColorKey myFallbackColorKey;
 %0A%0A  
@@ -1281,35 +1281,8 @@
 olor
-, ColorKey fallBackColorKey
 ) %7B%0A
@@ -1355,51 +1355,8 @@
 or;%0A
-    myFallbackColorKey = fallBackColorKey;%0A
   %7D%0A
@@ -1482,17 +1482,20 @@
 alName, 
-s
+name
  -%3E new 
@@ -1507,14 +1507,12 @@
 Key(
-s,null
+name
 ,nul
@@ -1874,16 +1874,30 @@
 ullable%0A
+  @Deprecated%0A
   public
@@ -1941,34 +1941,20 @@
  return 
-myFallbackColorKey
+null
 ;%0A  %7D%0A%0A 
@@ -2083,995 +2083,8 @@
  %7D%0A%0A
-  @NotNull%0A  public static ColorKey createColorKey(@NonNls @NotNull String externalName, @Nullable ColorKey fallbackColorKey) %7B%0A    ColorKey existing = ourRegistry.get(externalName);%0A    if (existing != null) %7B%0A      if (Comparing.equal(existing.getFallbackColorKey(), fallbackColorKey)) return existing;%0A      // some crazy life cycle assumes we can overwrite color%0A      ourRegistry.remove(externalName, existing);%0A    %7D%0A    ColorKey newKey = new ColorKey(externalName, existing == null ? null : existing.getDefaultColor(), fallbackColorKey);%0A    ColorKey res = ConcurrencyUtil.cacheOrGet(ourRegistry, externalName, newKey);%0A%0A    if (fallbackColorKey != null) %7B%0A      JBIterable%3CColorKey%3E it = JBIterable.generate(fallbackColorKey, o -%3E o == res ? null : o.myFallbackColorKey);%0A      if (it.find(o -%3E o == res) == res) %7B%0A        String cycle = StringUtil.join(it.map(ColorKey::getExternalName), %22-%3E%22);%0A        LOG.error(%22Cycle detected: %22 + cycle);%0A      %7D%0A    %7D%0A%0A    return res;%0A  %7D%0A%0A
   @N
@@ -2727,66 +2727,8 @@
 olor
-, existing == null ? null : existing.getFallbackColorKey()
 );%0A 

remove unused fallbackKey