package com.siyeh.ig.classmetrics;

import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.psi.PsiAnonymousClass;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiTypeParameter;
import com.siyeh.ig.BaseInspectionVisitor;
import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.Set;

public class ClassInheritanceDepthInspection
        extends ClassMetricInspection {
    public String getID(){
        return "ClassTooDeepInInheritanceTree";
    }
    private static final int CLASS_INHERITANCE_LIMIT = 2;

    public String getDisplayName() {
        return "Class too deep in inheritance tree";
    }

    public String getGroupDisplayName() {
        return GroupNames.CLASSMETRICS_GROUP_NAME;
    }

    protected int getDefaultLimit() {
        return CLASS_INHERITANCE_LIMIT;
    }

    protected String getConfigurationLabel() {
        return "Inheritance depth limit:";
    }

    public String buildErrorString(PsiElement location) {
        final PsiClass aClass = (PsiClass) location.getParent();
        final int count = getInheritanceDepth(aClass, new HashSet<PsiClass>());
        return "#ref is too deep in inheritance tree (inheritance depth = " + count + ") #loc";
    }

    public BaseInspectionVisitor buildVisitor() {
        return new ClassNestingLevel();
    }

    private class ClassNestingLevel extends BaseInspectionVisitor {

        public void visitClass(@NotNull PsiClass aClass) {
            if (aClass.isEnum()) {
                return;
            }
            if(aClass instanceof PsiTypeParameter ||
                    aClass instanceof PsiAnonymousClass){
                return;
            }
            // note: no call to super

            final int inheritanceDepth = getInheritanceDepth(aClass, new HashSet<PsiClass>());
            if (inheritanceDepth <= getLimit()) {
                return;
            }
            registerClassError(aClass);
        }
    }

    private int getInheritanceDepth(PsiClass aClass, Set<PsiClass> visited) {
        if (visited.contains(aClass)) {
            return 0;
        }
        visited.add(aClass);
        final PsiClass[] supers = aClass.getSupers();
        if (supers == null || supers.length == 0) {
            return 0;
        }
        int maxAncestorDepth = 0;
        for(PsiClass aSuper : supers){
            if(aSuper == null)
            {
                continue;
            }
           final int ancestorDepth = getInheritanceDepth(aSuper, visited);
            if(ancestorDepth > maxAncestorDepth){
                maxAncestorDepth = ancestorDepth;
            }
        }
        return maxAncestorDepth + 1;
    }

}

@@ -452,17 +452,16 @@
 spection
- 
 %7B%0A    pu
@@ -531,24 +531,25 @@
 ree%22;%0A    %7D%0A
+%0A
     private 
@@ -621,33 +621,32 @@
 getDisplayName()
- 
 %7B%0A        return
@@ -730,17 +730,16 @@
 ayName()
- 
 %7B%0A      
@@ -825,17 +825,16 @@
 tLimit()
- 
 %7B%0A      
@@ -918,17 +918,16 @@
 nLabel()
- 
 %7B%0A      
@@ -1025,17 +1025,16 @@
 ocation)
- 
 %7B%0A      
@@ -1247,16 +1247,32 @@
 epth = %22
+%0A               
  + count
@@ -1338,17 +1338,16 @@
 isitor()
- 
 %7B%0A      
@@ -1452,19 +1452,17 @@
 nVisitor
- %7B%0A
+%7B
 %0A       
@@ -1510,17 +1510,16 @@
  aClass)
- 
 %7B%0A      
@@ -1526,17 +1526,16 @@
       if
- 
 (aClass.
@@ -1543,17 +1543,16 @@
 sEnum())
- 
 %7B%0A      
@@ -1831,32 +1831,93 @@
 nceDepth(aClass,
+%0A                                                            
  new HashSet%3CPsi
@@ -1941,17 +1941,16 @@
       if
- 
 (inherit
@@ -1973,17 +1973,16 @@
 Limit())
- 
 %7B%0A      
@@ -2145,17 +2145,16 @@
 visited)
- 
 %7B%0A      
@@ -2157,17 +2157,16 @@
       if
- 
 (visited
@@ -2183,17 +2183,16 @@
 aClass))
- 
 %7B%0A      
@@ -2272,16 +2272,18 @@
 lass
-%5B%5D
  super
+Clas
 s = 
@@ -2297,16 +2297,20 @@
 getSuper
+Clas
 s();%0A   
@@ -2320,15 +2320,18 @@
   if
- 
 (super
+Clas
 s ==
@@ -2339,32 +2339,9 @@
 null
- %7C%7C supers.length == 0) 
+)
 %7B%0A  
@@ -2382,194 +2382,14 @@
     
-int maxAncestorDepth = 0;%0A        for(PsiClass aSuper : supers)%7B%0A            if(aSuper == null)%0A            %7B%0A                continue;%0A            %7D%0A           final int ancestorDepth =
+return
  get
@@ -2409,14 +2409,18 @@
 pth(
-aS
+s
 uper
+Class
 , vi
@@ -2429,165 +2429,8 @@
 ted)
-;%0A            if(ancestorDepth %3E maxAncestorDepth)%7B%0A                maxAncestorDepth = ancestorDepth;%0A            %7D%0A        %7D%0A        return maxAncestorDepth
  + 1
@@ -2437,11 +2437,10 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A

Fix for IDEA-1389