package com.github.mkolisnyk.cucumber.runner;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ArrayUtils;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.InitializationError;

import com.cedarsoftware.util.io.JsonWriter;
import com.github.mkolisnyk.cucumber.reporting.CucumberCustomReport;
import com.github.mkolisnyk.cucumber.reporting.CucumberSplitFeature;
import com.github.mkolisnyk.cucumber.reporting.types.result.CucumberFeatureResult;
import com.github.mkolisnyk.cucumber.reporting.types.result.CucumberScenarioResult;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

public class ExtendedParallelScenarioCucumber extends Runner {

    private Class<?> clazz;
    private CucumberOptions cucumberOptions;
    private ExtendedCucumberOptions[] extendedCucumberOptions;
    
    public ExtendedParallelScenarioCucumber(Class<?> testClass) {
        super();
        this.clazz = testClass;
        this.cucumberOptions = testClass.getAnnotation(CucumberOptions.class);
        this.extendedCucumberOptions = testClass.getAnnotationsByType(ExtendedCucumberOptions.class);
    }
    @Override
    public Description getDescription() {
        return Description.createTestDescription(clazz, clazz.getCanonicalName());
    }
    public static Annotation setAttrValue(Annotation anno, Class<? extends Annotation> type, String attrName, Object newValue) throws Exception {
        InvocationHandler handler = new AnnotationInvocationHandler(anno, attrName, newValue);
        Annotation proxy = (Annotation) Proxy.newProxyInstance(anno.getClass().getClassLoader(), new Class[]{type}, handler);
        return proxy;
    }
    @Override
    public void run(RunNotifier notifier) {
        try {
            Annotation anno = (Annotation) cucumberOptions;
            CucumberOptions dryRunOptions = (CucumberOptions) ExtendedParallelScenarioCucumber.setAttrValue(
                    cucumberOptions, CucumberOptions.class, "dryRun", true);
            ExtendedCucumber cucumber = new ExtendedCucumber(this.clazz, dryRunOptions, extendedCucumberOptions, false);
            cucumber.run(notifier);
            String jsonFile = "";
            for (String plugin : cucumberOptions.plugin()) {
                if (plugin.startsWith("json:")) {
                    jsonFile = plugin.substring("json:".length());
                }
            }
            System.out.println("JSON file: " + jsonFile);
            CucumberSplitFeature report = new CucumberSplitFeature();
            String outputFolder = new File(jsonFile).getParentFile().getAbsolutePath() + File.separator + "features";
            report.setOutputDirectory(outputFolder);
            report.setSourceFile(jsonFile);
            report.execute(true);
            
            CucumberOptions parallelRunOptions = (CucumberOptions) ExtendedParallelScenarioCucumber.setAttrValue(
                    cucumberOptions, CucumberOptions.class, "features", new String[] {outputFolder});
            ExtendedParallelCucumber parallelRunner = new ExtendedParallelCucumber(clazz, parallelRunOptions, extendedCucumberOptions);
            parallelRunner.run(notifier);
            
            String[] paths = parallelRunner.getOutputJsonPaths(false);
            Map<String, CucumberFeatureResult> featureIdMap = new LinkedHashMap<String, CucumberFeatureResult>();
            for (String path : paths) {
                System.out.println("Processing file: " + path);
                CucumberFeatureResult[] features = report.readFileContent(path, false);
                for (CucumberFeatureResult feature : features) {
                    String tag = feature.getTags()[0].getName();
                    System.out.println("Getting tag: " + tag);
                    if (featureIdMap.containsKey(tag)) {
                        CucumberFeatureResult currentResult = featureIdMap.get(tag);
                        CucumberScenarioResult[] scenarios = currentResult.getElements();
                        scenarios = (CucumberScenarioResult[]) ArrayUtils.addAll(scenarios, feature.getElements());
                        currentResult.setElements(scenarios);
                        featureIdMap.put(tag, currentResult);
                    } else {
                        featureIdMap.put(tag, feature);
                    }
                }
            }
            List<CucumberFeatureResult> consolidatedFeatures = new ArrayList<CucumberFeatureResult>();
            for (Entry<String, CucumberFeatureResult> entry : featureIdMap.entrySet()) {
                consolidatedFeatures.add(entry.getValue());
            }
            String json = JsonWriter.objectToJson(consolidatedFeatures);
            FileUtils.writeStringToFile(new File("target/final.json"), json);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

@@ -105,40 +105,8 @@
 on;%0A
-import java.lang.reflect.Field;%0A
 impo
@@ -181,36 +181,8 @@
 xy;%0A
-import java.util.ArrayList;%0A
 impo
@@ -213,31 +213,8 @@
 ap;%0A
-import java.util.List;%0A
 impo
@@ -264,48 +264,8 @@
 y;%0A%0A
-import org.apache.commons.io.FileUtils;%0A
 impo
@@ -426,213 +426,8 @@
 er;%0A
-import org.junit.runners.ParentRunner;%0Aimport org.junit.runners.model.InitializationError;%0A%0Aimport com.cedarsoftware.util.io.JsonWriter;%0Aimport com.github.mkolisnyk.cucumber.reporting.CucumberCustomReport;
 %0Aimp
@@ -658,16 +658,92 @@
 oResult;
+%0Aimport com.github.mkolisnyk.cucumber.runner.runtime.ExtendedRuntimeOptions;
 %0A%0Aimport
@@ -776,44 +776,8 @@
 ons;
-%0Aimport cucumber.api.junit.Cucumber;
 %0A%0Apu
@@ -1897,68 +1897,8 @@
 y %7B%0A
-            Annotation anno = (Annotation) cucumberOptions;%0A
     
@@ -2484,66 +2484,8 @@
   %7D%0A
-            System.out.println(%22JSON file: %22 + jsonFile);%0A
     
@@ -3448,72 +3448,8 @@
 ) %7B%0A
-                System.out.println(%22Processing file: %22 + path);%0A
     
@@ -3524,20 +3524,19 @@
 t(path, 
-fals
+tru
 e);%0A    
@@ -3665,71 +3665,8 @@
 ();%0A
-                    System.out.println(%22Getting tag: %22 + tag);%0A
     
@@ -4284,21 +4284,16 @@
         
-List%3C
 Cucumber
@@ -4305,17 +4305,18 @@
 reResult
-%3E
+%5B%5D
  consoli
@@ -4332,49 +4332,109 @@
 ures
- = new ArrayList%3CCucumberFeatureResult%3E()
+%0A            %09%09= new CucumberFeatureResult%5BfeatureIdMap.entrySet().size()%5D;%0A            int index = 0
 ;%0A  
@@ -4560,13 +4560,18 @@
 ures
-.add(
+%5Bindex%5D = 
 entr
@@ -4582,17 +4582,16 @@
 tValue()
-)
 ;%0A      
@@ -4588,33 +4588,44 @@
 ();%0A            
-%7D
+    index++;
 %0A            Str
@@ -4625,146 +4625,195 @@
     
-String json = JsonWriter.objectToJson(consolidatedFeatures);%0A            FileUtils.writeStringToFile(new File(%22target/final.js
+%7D%0A            for (ExtendedCucumberOptions option : this.extendedCucumberOptions) %7B%0A            %09%09ReportRunner.run(new ExtendedRuntimeOptions(opti
 on
-%22
 ), 
-json);
+consolidatedFeatures);%0A            %7D
 %0A   

fix for parallel run results collection