// Path: src/main/java/javafixes/common/function/Task.java
// @FunctionalInterface
// public interface Task {
// 
//     /**
//      * Executes a task or throws an exception if unable to do so.
//      *
//      * @throws Exception if unable to execute task
//      * @see Runner
//      * @see MonitoringTaskSubmitter
//      */
//     void run() throws Exception;
// }


import javafixes.common.function.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
package javafixes.concurrency;



/**
 * A wrapper around {@link java.util.concurrent.ScheduledExecutorService ScheduledExecutorService}
 * that allows you to monitor the number of submitted, failed and succeeded task, plus has the
 * ability to wait until all tasks scheduled trough {@code MonitoringTaskSubmitter} are completed
 * = there are no scheduled or running tasks.
 *
 * @author mtymes
 * @since 10/22/14 10:41 PM
 */
public class MonitoringTaskSubmitter {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final AtomicInteger failedToSubmit = new AtomicInteger(0);
    private final AtomicInteger succeeded = new AtomicInteger(0);
    private final AtomicInteger failed = new AtomicInteger(0);

    protected final ReusableCountLatch latch = new ReusableCountLatch();

    protected final ScheduledExecutorService executor;

    /**
     * @param executor executor that will be used to execute tasks
     */
    public MonitoringTaskSubmitter(ScheduledExecutorService executor) {
        this.executor = executor;
    }

    /**
     * Schedules a {@link Callable} for immediate execution.
     * It might be executed later though if the {@link ScheduledExecutorService} has no available threads
     * or more tasks are queued for execution before this task.
     *
     * @param callable {@link Callable} to be executed
     * @param <T>      type of return value
     * @return {@link Future} referring to the state of submitted {@link Callable}
     */
    public <T> Future<T> run(Callable<T> callable) {
        return submit(asMonitoredCallable(callable));
    }

    /**
     * Schedules a {@link Task} for immediate execution
     * It might be executed later though if the {@link ScheduledExecutorService} has no available threads
     * or more tasks are queued for execution before this task.
     *
     * @param task {@link Task} to be executed
     * @return {@link Future} referring to the state of submitted {@link Task}
     */
// Path: src/main/java/javafixes/common/function/Task.java
// @FunctionalInterface
// public interface Task {
// 
//     /**
//      * Executes a task or throws an exception if unable to do so.
//      *
//      * @throws Exception if unable to execute task
//      * @see Runner
//      * @see MonitoringTaskSubmitter
//      */
//     void run() throws Exception;
// }


// Path: src/main/java/javafixes/concurrency/MonitoringTaskSubmitter.java
import javafixes.common.function.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

package javafixes.concurrency;



/**
 * A wrapper around {@link java.util.concurrent.ScheduledExecutorService ScheduledExecutorService}
 * that allows you to monitor the number of submitted, failed and succeeded task, plus has the
 * ability to wait until all tasks scheduled trough {@code MonitoringTaskSubmitter} are completed
 * = there are no scheduled or running tasks.
 *
 * @author mtymes
 * @since 10/22/14 10:41 PM
 */
public class MonitoringTaskSubmitter {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final AtomicInteger failedToSubmit = new AtomicInteger(0);
    private final AtomicInteger succeeded = new AtomicInteger(0);
    private final AtomicInteger failed = new AtomicInteger(0);

    protected final ReusableCountLatch latch = new ReusableCountLatch();

    protected final ScheduledExecutorService executor;

    /**
     * @param executor executor that will be used to execute tasks
     */
    public MonitoringTaskSubmitter(ScheduledExecutorService executor) {
        this.executor = executor;
    }

    /**
     * Schedules a {@link Callable} for immediate execution.
     * It might be executed later though if the {@link ScheduledExecutorService} has no available threads
     * or more tasks are queued for execution before this task.
     *
     * @param callable {@link Callable} to be executed
     * @param <T>      type of return value
     * @return {@link Future} referring to the state of submitted {@link Callable}
     */
    public <T> Future<T> run(Callable<T> callable) {
        return submit(asMonitoredCallable(callable));
    }

    /**
     * Schedules a {@link Task} for immediate execution
     * It might be executed later though if the {@link ScheduledExecutorService} has no available threads
     * or more tasks are queued for execution before this task.
     *
     * @param task {@link Task} to be executed
     * @return {@link Future} referring to the state of submitted {@link Task}
     */
    public Future<Void> run(Task task) {