/*
 * Copyright 2000-2009 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.util.xml.impl;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.ReflectionCache;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomReflectionUtil;
import com.intellij.util.xml.Implementation;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Nullable;

import java.util.Comparator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * @author peter
 */
class ImplementationClassCache extends ConcurrentFactoryMap<Class<? extends DomElement>, Class<? extends DomElement>> {
  private static final Comparator<Class<? extends DomElement>> CLASS_COMPARATOR = new Comparator<Class<? extends DomElement>>() {
    public int compare(final Class<? extends DomElement> o1, final Class<? extends DomElement> o2) {
      if (o1.isAssignableFrom(o2)) return 1;
      if (o2.isAssignableFrom(o1)) return -1;
      if (o1.equals(o2)) return 0;
      throw new AssertionError("Incompatible implementation classes: " + o1 + " & " + o2);
    }
  };


  private final Map<Class<? extends DomElement>, Class<? extends DomElement>> myImplementationClasses =
    new THashMap<Class<? extends DomElement>, Class<? extends DomElement>>();

  @Nullable
  protected Class<? extends DomElement> create(final Class<? extends DomElement> concreteInterface) {
    final TreeSet<Class<? extends DomElement>> set = new TreeSet<Class<? extends DomElement>>(CLASS_COMPARATOR);
    findImplementationClassDFS(concreteInterface, set);
    if (!set.isEmpty()) {
      return set.first();
    }
    final Implementation implementation = DomReflectionUtil.findAnnotationDFS(concreteInterface, Implementation.class);
    return implementation == null ? null : implementation.value();
  }

  private void findImplementationClassDFS(final Class concreteInterface, SortedSet<Class<? extends DomElement>> results) {
    Class<? extends DomElement> aClass = myImplementationClasses.get(concreteInterface);
    if (aClass != null) {
      results.add(aClass);
    }
    else {
      for (final Class aClass1 : ReflectionCache.getInterfaces(concreteInterface)) {
        findImplementationClassDFS(aClass1, results);
      }
    }
  }

  public final void registerImplementation(final Class<? extends DomElement> domElementClass, Class<? extends DomElement> implementationClass,
                                           final Disposable parentDisposable) {
    myImplementationClasses.put(domElementClass, implementationClass);
    if (parentDisposable != null) {
      Disposer.register(parentDisposable, new Disposable() {
        public void dispose() {
          myImplementationClasses.remove(domElementClass);
        }
      });
    }
    super.clear();
  }

}

@@ -818,49 +818,8 @@
 ap;%0A
-import com.intellij.util.xml.DomElement;%0A
 impo
@@ -1143,95 +1143,8 @@
 ache
- extends ConcurrentFactoryMap%3CClass%3C? extends DomElement%3E, Class%3C? extends DomElement%3E%3E
  %7B%0A 
@@ -1181,38 +1181,16 @@
 or%3CClass
-%3C? extends DomElement%3E
 %3E CLASS_
@@ -1222,38 +1222,16 @@
 or%3CClass
-%3C? extends DomElement%3E
 %3E() %7B%0A  
@@ -1266,68 +1266,24 @@
 lass
-%3C? extends DomElement%3E o1, final Class%3C? extends DomElement%3E
+ o1, final Class
  o2)
@@ -1544,59 +1544,15 @@
 lass
-%3C? extends DomElement%3E, Class%3C? extends DomElement%3E
+, Class
 %3E my
@@ -1574,20 +1574,16 @@
 lasses =
-%0A   
  new THa
@@ -1597,65 +1597,128 @@
 lass
-%3C? extends DomElement%3E, Class%3C? extends DomElement%3E%3E();%0A%0A
+, Class%3E();%0A  private final ConcurrentFactoryMap%3CClass, Class%3E myCache = new ConcurrentFactoryMap%3CClass, Class%3E() %7B%0A    
   @N
@@ -1725,16 +1725,22 @@
 ullable%0A
+      
   protec
@@ -1752,71 +1752,27 @@
 lass
-%3C? extends DomElement%3E create(final Class%3C? extends DomElement%3E
+ create(final Class
  con
@@ -1785,24 +1785,30 @@
 nterface) %7B%0A
+      
     final Tr
@@ -1818,38 +1818,16 @@
 et%3CClass
-%3C? extends DomElement%3E
 %3E set = 
@@ -1843,38 +1843,16 @@
 et%3CClass
-%3C? extends DomElement%3E
 %3E(CLASS_
@@ -1864,16 +1864,22 @@
 RATOR);%0A
+      
     find
@@ -1926,16 +1926,22 @@
 , set);%0A
+      
     if (
@@ -1954,24 +1954,30 @@
 sEmpty()) %7B%0A
+      
       return
@@ -1990,26 +1990,38 @@
 irst();%0A    
-%7D%0A
+      %7D%0A      
     final Im
@@ -2124,24 +2124,30 @@
 ion.class);%0A
+      
     return i
@@ -2203,17 +2203,30 @@
 ue();%0A  
-%7D
+      %7D%0A    %7D;
 %0A%0A  priv
@@ -2311,74 +2311,30 @@
 lass
-%3C? extends DomElement%3E%3E results) %7B%0A    Class%3C? extends DomElement%3E
+%3E results) %7B%0A    Class
  aCl
@@ -2669,38 +2669,16 @@
 al Class
-%3C? extends DomElement%3E
  domElem
@@ -2696,30 +2696,8 @@
 lass
-%3C? extends DomElement%3E
  imp
@@ -3087,13 +3087,131 @@
     
-super
+myCache.clear();%0A  %7D%0A%0A  public Class get(Class key) %7B%0A    return myCache.get(key);%0A  %7D%0A%0A  public void clear() %7B%0A    myCache
 .cle

remove wildcards getting in the way