package ru.yandex.wmtools.common.util.concurrent;

import ru.yandex.common.util.functional.Function;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * User: azakharov
 * Date: 12.04.12
 * Time: 12:00
 */
public class ParallelMap<X,Y> {
    private final ExecutorService executorService;

    public ParallelMap(final ExecutorService executorService) {
        this.executorService = executorService;
    }

    /**
     * Выполняет функцию f в отдельном потоке для каждого аргумента x из xs.
     *
     * @param xs                        набор аргументов функции, обработка которых выполняется параллельно
     * @param f                         функция
     * @return                          набор результатов выполнения функции
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public Iterable<Y> parMap(final Iterable<X> xs, final Function<X,Y> f) throws ExecutionException, InterruptedException {
        final List<Future<Y>> results = new LinkedList<Future<Y>>();
        synchronized (executorService) {
            for (final X x : xs) {
                final Future<Y> future = executorService.submit(new ParallelMapTask<X, Y>(x, f));
                results.add(future);
            }
        }
        final List<Y> ys = new LinkedList<Y>();
        for (final Future<Y> r : results) {
            ys.add(r.get());
        }
        return ys;
    }
}
