package de.is24.deadcode4j.analyzer;

import com.google.common.collect.Lists;
import de.is24.deadcode4j.AnalysisContext;
import de.is24.deadcode4j.AnalysisSink;
import de.is24.deadcode4j.AnalyzedCode;
import de.is24.deadcode4j.DeadCodeComputer;
import javassist.CtClass;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newHashSetWithExpectedSize;

public class IgnoreClassesAnalyzer extends ByteCodeAnalyzer {

    @Nonnull
    private final Set<String> classesToIgnore;
    @Nonnull
    private final Set<String> ignoredClasses;

    public IgnoreClassesAnalyzer(@Nonnull Set<String> classesToIgnore) {
        this.classesToIgnore = newHashSet(classesToIgnore);
        this.ignoredClasses = newHashSetWithExpectedSize(classesToIgnore.size());
    }

    @Override
    protected void analyzeClass(@Nonnull AnalysisContext analysisContext, @Nonnull CtClass clazz) {
        String className = clazz.getName();
        analysisContext.addAnalyzedClass(className);
        if (classesToIgnore.contains(className)) {
            this.ignoredClasses.add(className);
        }
    }

    @Override
    public void finishAnalysis(@Nonnull AnalysisSink analysisSink, @Nonnull AnalyzedCode analyzedCode) {
        ArrayList<String> ignoredButUnknownClasses = Lists.newArrayList(this.classesToIgnore);
        ignoredButUnknownClasses.removeAll(this.ignoredClasses);
        for (String ignoredButUnknownClass : ignoredButUnknownClasses) {
            logger.warn("Class [{}] should be ignored, but does not exist. You should remove the configuration entry.",
                    ignoredButUnknownClass);
        }

        Collection<String> deadClasses = new DeadCodeComputer().computeDeadCode(analyzedCode).getDeadClasses();
        ArrayList<String> ignoredButExistingClasses = Lists.newArrayList(this.ignoredClasses);
        ignoredButExistingClasses.removeAll(deadClasses);
        for (String ignoredButExistingClass : ignoredButExistingClasses) {
            logger.warn("Class [{}] should be ignored, but is not dead. You should remove the configuration entry.",
                    ignoredButExistingClass);
            this.ignoredClasses.remove(ignoredButExistingClass);
        }

        if (this.ignoredClasses.size() != 0) {
            logger.info("Ignoring {} class(es) which seem(s) to be unused.", this.ignoredClasses.size());
        }
        analysisSink.addDependencies("_IgnoredClasses_",
                this.ignoredClasses.toArray(new String[this.ignoredClasses.size()]));
    }

}

@@ -330,37 +330,8 @@
 st;%0A
-import java.util.Collection;%0A
 impo
@@ -480,16 +480,123 @@
 dSize;%0A%0A
+/**%0A * Analyzes class files: marks a class as being in use if it should be ignored.%0A *%0A * @since 2.0.0%0A */%0A
 public c
@@ -1434,24 +1434,303 @@
 yzedCode) %7B%0A
+        logUnknownClassesThatShouldBeIgnored();%0A        logLiveClassesThatShouldBeIgnored(analyzedCode);%0A        logIgnoredClasses();%0A%0A        analysisSink.addDependencies(%22_IgnoredClasses_%22, this.ignoredClasses);%0A    %7D%0A%0A    private void logUnknownClassesThatShouldBeIgnored() %7B%0A
         Arra
@@ -2129,89 +2129,79 @@
   %7D%0A
-%0A
     
+%7D%0A%0A
     
-Collection%3CString%3E deadClasses = new DeadCodeComputer().computeDea
+private void logLiveClassesThatShouldBeIgnored(Analyze
 dCode
-(
+ 
 anal
@@ -2213,26 +2213,10 @@
 ode)
-.getDeadClasses();
+ %7B
 %0A   
@@ -2351,17 +2351,73 @@
 moveAll(
-d
+new DeadCodeComputer().computeDeadCode(analyzedCode).getD
 eadClass
@@ -2410,32 +2410,34 @@
 ).getDeadClasses
+()
 );%0A        for (
@@ -2732,24 +2732,69 @@
 ;%0A        %7D%0A
+    %7D%0A%0A    private void logIgnoredClasses() %7B
 %0A        if 
@@ -2949,151 +2949,8 @@
   %7D%0A
-        analysisSink.addDependencies(%22_IgnoredClasses_%22,%0A                this.ignoredClasses.toArray(new String%5Bthis.ignoredClasses.size()%5D));%0A
     

clean code; documentation added