package com.packt.tfesenko.multithreading.section1;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class Lesson4 {

	public static void main(String[] args) throws InterruptedException {
		AppleTree[] appleTrees = AppleTree.newTreeGarden(12);
		PickFruitAction task = new PickFruitAction(appleTrees, 0, appleTrees.length - 1);

		ForkJoinPool pool = ForkJoinPool.commonPool();

		pool.invoke(task);
		// try this: pool.execute(task); 
		// try this: pool.execute(task); task.join();
		// try this: pool.execute(task); pool.awaitTermination(10, TimeUnit.SECONDS);

		System.out.println();
		System.out.println("Done!");
	}

	public static class PickFruitAction extends RecursiveAction {

		private final AppleTree[] appleTrees;
		private final int startInclusive;
		private final int endInclusive;

		private final int taskThreadshold = 4;

		public PickFruitAction(AppleTree[] array, int startInclusive, int endInclusive) {
			this.appleTrees = array;
			this.startInclusive = startInclusive;
			this.endInclusive = endInclusive;
		}

		@Override
		protected void compute() {
			if (endInclusive - startInclusive < taskThreadshold) {
				doCompute();
				return;
			}
			int midpoint = startInclusive + (endInclusive - startInclusive) / 2;

			PickFruitAction leftSum = new PickFruitAction(appleTrees, startInclusive, midpoint);
			PickFruitAction rightSum = new PickFruitAction(appleTrees, midpoint + 1, endInclusive);

			rightSum.fork(); // computed asynchronously
			leftSum.compute();// computed synchronously: immediately and in the current thread
			rightSum.join();
		}

		protected void doCompute() {
			IntStream.rangeClosed(startInclusive, endInclusive)//
					.forEach(i -> appleTrees[i].pickApples());

		}
	}
}