package koz01.java2.lab07;

import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Test;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class TestThread {

	@Test
	public void testThreads() {
		final ComplicatedProcess cp = new ComplicatedProcess();
		Collection<Thread> threads = new LinkedList<>();
		Collection<Long> durations = new LinkedList<>();
		long start = System.currentTimeMillis();
		for (int i = 0; i < 10; i++) {
			final int threadNu = i;
			Thread t = new Thread() {
				@Override
				public void run() {
					cp.doNop(l -> durations.add(l));
				};
			};
			t.start();
			threads.add(t);
		}
		threads.forEach(t -> {
			try {
				t.join();
			}
			catch (InterruptedException exc) {
				log.error("join", exc);
			}
		});
		long totalDuration = System.currentTimeMillis() - start;
		long maxDuration = durations.stream().mapToLong(l -> l).max().getAsLong();
		log.info("duration: {}/{} ms", maxDuration, totalDuration);
	}

	@Test
	public void testExecutors() {
		for (int i = 10; i <= 10; i++) {
			ExecutorService executorService = Executors.newFixedThreadPool(i);
			runExecutors(executorService, i);
			executorService.shutdown();
		}
	}

	private void runExecutors(ExecutorService executorService, int threads) {
		final ComplicatedProcess cp = new ComplicatedProcess();
		Collection<Future<Long>> futures = new LinkedList<>();

		long start = System.currentTimeMillis();
		for (int i = 0; i < 10; i++) {
			Future<Long> future = executorService.submit(() -> cp
				.doFactorialReturnDuration());
			futures.add(future);
		}

		Collection<Long> durations = futures.stream().map(f -> {
			try {
				return f.get();
			}
			catch (InterruptedException | ExecutionException exc) {
				log.error("error", exc.getCause());
				return -1l;
			}
		}).collect(Collectors.toList());
		long totalDuration = System.currentTimeMillis() - start;
		long maxDuration = durations.stream().mapToLong(l -> l).max().getAsLong();
		log.info("duration for #{} executors: {}/{} ms", threads, maxDuration,
			totalDuration);
	}

}