package org.ao;

import java.io.IOException;
import org.ao.suite.SuiteDriver;
import org.ao.suite.SuiteProperty;
import org.ao.suite.SuiteTask;
import org.ao.suite.test.command.exception.CommandNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
public class JSONRunnerMain {

	public static Logger AppLogger = LoggerFactory.getLogger(JSONRunnerMain.class);

	public static ApplicationContext AppContext;	
	public static SuiteProperty SuiteProp;
	
	public static void main(String[] args) {

		AppContext = SpringApplication.run(JSONRunnerMain.class, args);
		SuiteProp = AppContext.getBean(SuiteProperty.class);
		
		if (SuiteProp.isParallel && SuiteProp.parallelCount > 1)
			parallelRun();	
		else
			run();
			
		int exitCode = SpringApplication.exit(AppContext);
		if (exitCode != 0)
			AppLogger.error("Application exit code is {}.", exitCode);
		
	}

	public static void run() {
		SuiteDriver startUpSuite = AppContext.getBean(SuiteDriver.class);
		try {
			startUpSuite.Load(SuiteProp.startUp);
			AppLogger.debug("startup suite is loaded.");
			startUpSuite.RunTests();

		} catch (IOException | CommandNotFoundException e) {
			AppLogger.error("Program interrupted by {}", e);
			
		}
		finally {
			startUpSuite.destroy(); // !!! re-check this method's execution
		}
	}

	public static void parallelRun() {
		AppLogger.debug("Parallel Mode is ON.");
		List<SuiteTask> suiteTasks = new ArrayList<SuiteTask>();
		
		for (int i = 0; i < SuiteProp.parallelCount; i++) 
			suiteTasks.add(new SuiteTask(AppContext.getBean(SuiteDriver.class), SuiteProp.startUp));
			
		ExecutorService suiteExec = Executors.newFixedThreadPool(SuiteProp.parallelCount);
		try {
			suiteExec.invokeAll(suiteTasks);
		} catch (InterruptedException e) {
			AppLogger.error("Program interrupted by {}", e);
		}
		
		suiteExec.shutdown();
		try {
			suiteExec.awaitTermination(1, TimeUnit.MINUTES);
		} catch (InterruptedException e) {
			suiteExec.shutdownNow();
			try {
				suiteExec.awaitTermination(1, TimeUnit.MINUTES);
			} catch (InterruptedException e1) {
				
			}
		}
			
		AppLogger.debug("Suits finished in parallel.");
	}

}

@@ -486,24 +486,72 @@
 .util.List;%0A
+import java.util.concurrent.ExecutionException;%0A
 import java.
@@ -650,24 +650,96 @@
 current.
-TimeUnit
+Future;%0Aimport java.util.concurrent.TimeUnit;%0Aimport java.util.function.Consumer
 ;%0A%0A@Spri
@@ -1876,438 +1876,696 @@
 ;%0A%09%09
-List%3CSuiteTask%3E suiteTasks = new ArrayList%3CSuiteTask%3E();%0A%09%09%0A%09%09for (int i = 0; i %3C SuiteProp.parallelCount; i++) %0A%09%09%09suiteTasks.add(new SuiteTask(AppContext.getBean(SuiteDriver.class), SuiteProp.startUp));%0A%09%09%09%0A%09%09ExecutorService suiteExec = Executors.newFixedThreadPool(SuiteProp.parallelCount);%0A%09%09try %7B%0A%09%09%09suiteExec.invokeAll(suiteTasks);%0A%09%09%7D catch (InterruptedException e) %7B%0A%09%09%09AppLogger.error(%22Program interrupted by %7B%7D%22, e);%0A%09%09%7D
+%0A%09%09ExecutorService suiteExec = Executors.newWorkStealingPool();%0A%09%09List%3CSuiteTask%3E suiteTasks = new ArrayList%3CSuiteTask%3E();%0A%09%09final List%3CFuture%3CBoolean%3E%3E taskFutures = new ArrayList%3CFuture%3CBoolean%3E%3E();%0A%09%09Consumer%3CFuture%3CBoolean%3E%3E waitFor = f -%3E %7B%0A%09%09%09try %7B%0A%09%09%09%09f.get();%0A%09%09%09%7D catch (InterruptedException %7C ExecutionException e) %7B%0A%09%09%09%09AppLogger.error(%22one of is interrupted by %7B%7D%22, e);%0A%09%09%09%7D%0A%09%09%7D;  %0A%09%09%0A%09%09for (int i = 0; i %3C SuiteProp.parallelCount; i++) %0A%09%09%09suiteTasks.add(new SuiteTask(AppContext.getBean(SuiteDriver.class), SuiteProp.startUp));%0A%09%09%09%0A%09%09%0A%09%09suiteTasks.parallelStream()%0A%09%09%09.forEach(st -%3E taskFutures.add(suiteExec.submit(st)));%0A%09%09%0A%09%09taskFutures.parallelStream().forEach(waitFor);
 %0A%09%09%0A

change the way for wait all finish