package net.ssehub.kernel_haven.test_utils;

import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import net.ssehub.kernel_haven.SetUpException;
import net.ssehub.kernel_haven.analysis.AnalysisComponent;
import net.ssehub.kernel_haven.config.Configuration;

/**
 * Contains a helper method to execute analysis components.
 * 
 * @author Adam
 */
public class AnalysisComponentExecuter {

    /**
     * Don't allow any instances.
     */
    private AnalysisComponentExecuter() {
    }

    /**
     * Creates and executes the given {@link AnalysisComponent} class.
     * 
     * @param componentClass The component class to create and execute.
     * @param config The {@link Configuration} for the component. <code>null</code> if no special settings are needed.
     * @param inputs The input values for the component. The first dimension represent the different
     *      {@link AnalysisComponent} inputs; the second dimension represent that values that each input component
     *      should create.
     *      
     * @param <T> The output type of the analysis component.
     *      
     * @return The list of results that the component created.
     */
    public static <T> List<T> executeComponent(Class<?> componentClass, Configuration config, Object[]... inputs) {
        
        // create an empty configuration is none is passed to us
        if (config == null) {
            try {
                config = new TestConfiguration(new Properties());
            } catch (SetUpException e) {
                throw new RuntimeException("Can't create test configuration", e);
            }
        }
        
        // create input components based on the inputs parameter
        AnalysisComponent<?>[] inputComponents = new AnalysisComponent[inputs.length];
        for (int i = 0; i < inputs.length; i++) {
            try {
                inputComponents[i] = new TestAnalysisComponentProvider<>(inputs[i]);
            } catch (SetUpException e) {
                throw new RuntimeException("Can't create test input component", e);
            }
        }
        
        // create an array with the parameter types, to get the right constructor
        Class<?>[] parameterTypes = new Class[1 + inputComponents.length];
        parameterTypes[0] = Configuration.class;
        for (int i = 0; i < inputComponents.length; i++) {
            parameterTypes[i + 1] = AnalysisComponent.class;
        }
        
        // create an array with the parameter values, to pass to the consturctor
        Object[] parameterValues = new Object[1 + inputComponents.length];
        parameterValues[0] = config;
        for (int i = 0; i < inputComponents.length; i++) {
            parameterValues[i + 1] = inputComponents[i];
        }
        
        List<T> result = new LinkedList<>();
        
        try {
            // instantiate the component
            @SuppressWarnings("unchecked")
            AnalysisComponent<T> component = (AnalysisComponent<T>)
                    componentClass.getConstructor(parameterTypes).newInstance(parameterValues);
            
            // execute the component
            T r;
            while ((r = component.getNextResult()) != null) {
                result.add(r);
            }
            
        } catch (ReflectiveOperationException | ClassCastException | SecurityException e) {
            throw new RuntimeException("Can't instantiate analysis component", e);
        }
        
        return result;
    }
    
}

@@ -596,16 +596,1418 @@
      * %0A
+     * %3Cp%3E%0A     * Example usage:%3Cbr /%3E%0A     * Assuming that DummComponent is an AnalysisComponent, which returns Doubles and takes two input components,%0A     * one for Strings and one for Integers, and looks roughly like this:%0A     * %3Ccode%3E%0A     * %3Cpre%3E%0A     * public class DummyCoponent extends AnalysisComponent&lt;Double&gt; %7B%0A     *     public DummyCopmonent(Configuration config, AnalysisComponent&lt;String&gt; input1,%0A     *             AnalysisComponent&lt;Integer&gt; input2) %7B%0A     *         ...%0A     *     %7D%0A     *     ...%0A     * %7D%0A     * %3C/pre%3E%0A     * %3C/code%3E%0A     * %0A     * A call to %7B@link #executeComponent(Class, Configuration, Object%5B%5D...)%7D for this class would look like this:%0A     * %3Ccode%3E%0A     * %3Cpre%3E%0A     * List&lt;Double&gt; result = AnalysisComponentExecuter.executeComponent(%0A     *         DummyComponent.class, null,%0A     *         new Object%5B%5D %7B%0A     *             %22Some%22, %22Values%22, %22Here%22%0A     *         %7D,%0A     *         new Object%5B%5D %7B%0A     *             1, 2, 3%0A     *         %7D);%0A     * %3C/pre%3E%0A     * %3C/code%3E%0A     * %0A     * This would create two %7B@link TestAnalysisComponentProvider%7D, one for the three string values and one for the%0A     * three int values. It would then instantiate DummyComponent with an empty configuration and these two input%0A     * components. After this, it executes the DummyComponent and returns all the results as an array.%0A     * %3C/p%3E%0A     * %0A
      * @

Add example call to AnalysisComponentExecuter