package net.ssehub.kernel_haven.fe_analysis.fes;

import static net.ssehub.kernel_haven.util.null_checks.NullHelpers.notNull;

import net.ssehub.kernel_haven.SetUpException;
import net.ssehub.kernel_haven.analysis.AnalysisComponent;
import net.ssehub.kernel_haven.config.Configuration;
import net.ssehub.kernel_haven.fe_analysis.pcs.PcFinder.VariableWithPcs;
import net.ssehub.kernel_haven.util.OrderPreservingParallelizer;
import net.ssehub.kernel_haven.util.ProgressLogger;
import net.ssehub.kernel_haven.util.null_checks.NonNull;

/**
 * A {@link FeatureEffectFinder} that utilizes multiple threads. This helps with performance if simplification takes
 * long.
 * 
 * @author Adam
 */
public class ThreadedFeatureEffectFinder extends FeatureEffectFinder {

    private static final int NUM_THREADS = 6;
    
    /**
     * Creates a new {@link ThreadedFeatureEffectFinder} for the given PC finder.
     * 
     * @param config The global configuration.
     * @param pcFinder The component to get the PCs from.
     * 
     * @throws SetUpException If creating this component fails.
     */
    public ThreadedFeatureEffectFinder(@NonNull Configuration config,
            @NonNull AnalysisComponent<VariableWithPcs> pcFinder) throws SetUpException {
        super(config, pcFinder);
    }
    
    @Override
    protected void execute() {
        ProgressLogger progress = new ProgressLogger(notNull(getClass().getSimpleName()));
        
        OrderPreservingParallelizer<VariableWithPcs, VariableWithFeatureEffect> parallelizer
            = new OrderPreservingParallelizer<>(this::processSingle, (result) -> {
                if (result != null) {
                    addResult(result);
                }
                
                progress.processedOne();
                
            }, NUM_THREADS);
        
        VariableWithPcs pcs;
        while ((pcs = pcFinder.getNextResult()) != null) {
            parallelizer.add(pcs);
        }
        
        parallelizer.end();
        parallelizer.join();
        
        progress.close();
    }

}

@@ -275,24 +275,123 @@
 figuration;%0A
+import net.ssehub.kernel_haven.config.Setting;%0Aimport net.ssehub.kernel_haven.config.Setting.Type;%0A
 import net.s
@@ -451,16 +451,16 @@
 ithPcs;%0A
-
 import n
@@ -861,14 +861,13 @@
    p
-rivate
+ublic
  sta
@@ -880,27 +880,293 @@
 nal 
-int NUM_THREADS = 6
+@NonNull Setting%3C@NonNull Integer%3E THREAD_SETTING = new Setting%3C%3E(%0A            %22analysis.fe_finder.threads%22, Type.INTEGER, true, %224%22, %22Defines the number of threads the %22%0A            + ThreadedFeatureEffectFinder.class.getSimpleName() + %22 should use.%22);%0A    %0A    private int numThreads
 ;%0A  
@@ -1644,16 +1644,258 @@
 inder);%0A
+        %0A        config.registerSetting(THREAD_SETTING);%0A        numThreads = config.getValue(THREAD_SETTING);%0A        %0A        if (numThreads %3C 1) %7B%0A            throw new SetUpException(%22Number of threads can't be %22 + numThreads);%0A        %7D%0A
     %7D%0A  
@@ -2407,19 +2407,18 @@
  %7D, 
-NUM_THREADS
+numThreads
 );%0A 

Make number of threads in ThreadedFeatureEffectFinder configurable