/*
 * Copyright 2010-2015 Institut Pasteur.
 * 
 * This file is part of Icy.
 * 
 * Icy is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Icy is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
 */
package icy.system.thread;

import icy.main.Icy;
import icy.system.IcyExceptionHandler;
import icy.system.SystemUtil;

import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Processor class.<br>
 * Allow you to queue and execute tasks on a defined set of thread.
 * 
 * @author stephane
 */
public class Processor extends ThreadPoolExecutor
{
    public static final int DEFAULT_MAX_WAITING = 1024;
    public static final int DEFAULT_MAX_PROCESSING = SystemUtil.getNumberOfCPUs();

    /**
     * @deprecated Useless interface
     */
    @Deprecated
    public interface ProcessorEventListener extends EventListener
    {
        public void processDone(Processor source, Runnable runnable);
    }

    protected class ProcessorThreadFactory implements ThreadFactory
    {
        String name;

        public ProcessorThreadFactory(String name)
        {
            super();

            setName(name);
        }

        public String getName()
        {
            return name;
        }

        public void setName(String value)
        {
            this.name = value;
        }

        String getThreadName()
        {
            String result = name;

            return result;
        }

        @Override
        public Thread newThread(Runnable r)
        {
            final Thread result = new Thread(r, getThreadName());

            result.setPriority(priority);

            return result;
        }
    }

    protected class ProcessorRejectedExecutionHandler implements RejectedExecutionHandler
    {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor)
        {
            // ignore if we try to submit process while Icy is exiting
            if (!Icy.isExiting())
                throw new RejectedExecutionException("Cannot add new task, ignore execution of " + r);
        }
    }

    protected class FutureTaskAdapter<T> extends FutureTask<T>
    {
        public Runnable runnable;
        public Callable<T> callable;
        final boolean handleException;

        public FutureTaskAdapter(Runnable runnable, T result, boolean handleException)
        {
            super(runnable, result);

            this.runnable = runnable;
            this.callable = null;
            this.handleException = handleException;
        }

        public FutureTaskAdapter(Runnable runnable, boolean handleException)
        {
            this(runnable, null, handleException);
        }

        public FutureTaskAdapter(Callable<T> callable, boolean handleException)
        {
            super(callable);

            this.runnable = null;
            this.callable = callable;
            this.handleException = handleException;
        }

        @Override
        protected void done()
        {
            super.done();

            if (handleException)
            {
                try
                {
                    get();
                }
                catch (Exception e)
                {
                    IcyExceptionHandler.handleException(e.getCause(), true);
                }
            }
        }
    }

    /**
     * @deprecated
     */
    @Deprecated
    protected class RunnableAdapter implements Runnable
    {
        private final Runnable task;
        private final boolean onEDT;

        public RunnableAdapter(Runnable runnable, boolean onEDT)
        {
            super();

            task = runnable;
            this.onEDT = onEDT;
        }

        @Override
        public void run()
        {
            if (task != null)
            {
                if (onEDT)
                    ThreadUtil.invokeNow(task);
                else
                    task.run();
            }
        }

        /**
         * @return the task
         */
        public Runnable getTask()
        {
            return task;
        }
    }

    /**
     * @deprecated
     */
    @Deprecated
    protected class CallableAdapter<T> implements Callable<T>
    {
        private final Callable<T> task;
        private final boolean onEDT;

        public CallableAdapter(Callable<T> task, boolean onEDT)
        {
            super();

            this.task = task;
            this.onEDT = onEDT;
        }

        /**
         * @return the task
         */
        public Callable<T> getTask()
        {
            return task;
        }

        @Override
        public T call() throws Exception
        {
            if (task != null)
            {
                if (onEDT)
                    return ThreadUtil.invokeNow(task);

                return task.call();
            }

            return null;
        }
    }

    /**
     * @deprecated
     */
    @Deprecated
    protected class FutureTaskAdapterEDT<T> extends FutureTaskAdapter<T>
    {
        public FutureTaskAdapterEDT(Runnable runnable, T result, boolean onEDT)
        {
            super(new RunnableAdapter(runnable, onEDT), result, true);

            // assign the original runnable
            this.runnable = runnable;
            this.callable = null;
        }

        public FutureTaskAdapterEDT(Runnable runnable, boolean onEDT)
        {
            this(runnable, null, onEDT);
        }

        public FutureTaskAdapterEDT(Callable<T> callable, boolean onEDT)
        {
            super(new CallableAdapter<T>(callable, onEDT), true);

            // assign the original callable
            this.runnable = null;
            this.callable = callable;
        }

        public Runnable getRunnable()
        {
            return runnable;
        }

        public Callable<T> getCallable()
        {
            return callable;
        }
    }

    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = Thread.MIN_PRIORITY;

    /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = Thread.NORM_PRIORITY;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = Thread.MAX_PRIORITY;

    /**
     * parameters
     */
    int priority;

    /**
     * internal
     */
    protected Runnable waitingExecution;
    protected long lastAdd;

    /**
     * Create a new Processor with specified number of maximum waiting and processing tasks.<br>
     * 
     * @param maxWaiting
     *        The length of waiting queue.
     * @param numThread
     *        The maximum number of processing thread.
     * @param priority
     *        Processor priority<br>
     *        <code>Processor.MIN_PRIORITY</code><br>
     *        <code>Processor.NORM_PRIORITY</code><br>
     *        <code>Processor.MAX_PRIORITY</code>
     */
    public Processor(int maxWaiting, int numThread, int priority)
    {
        super(numThread, numThread, 2L, TimeUnit.SECONDS, (maxWaiting == -1) ? new LinkedBlockingQueue<Runnable>()
                : new LinkedBlockingQueue<Runnable>(maxWaiting));

        setThreadFactory(new ProcessorThreadFactory("Processor"));
        setRejectedExecutionHandler(new ProcessorRejectedExecutionHandler());
        allowCoreThreadTimeOut(true);

        this.priority = priority;

        waitingExecution = null;
    }

    /**
     * Create a new Processor with specified number of maximum waiting and processing tasks.
     * 
     * @param maxWaiting
     *        The length of waiting queue.
     * @param numThread
     *        The maximum number of processing thread.
     */
    public Processor(int maxWaiting, int numThread)
    {
        this(maxWaiting, numThread, NORM_PRIORITY);
    }

    /**
     * Create a new Processor with specified number of processing thread.
     * 
     * @param numThread
     *        The maximum number of processing thread.
     */
    public Processor(int numThread)
    {
        this(-1, numThread, NORM_PRIORITY);
    }

    /**
     * Create a new Processor with default number of maximum waiting and processing tasks.
     */
    public Processor()
    {
        this(DEFAULT_MAX_WAITING, DEFAULT_MAX_PROCESSING);
    }

    /**
     * @deprecated Use {@link #removeFirstWaitingTask(Runnable)} instead.
     */
    @Deprecated
    public boolean removeTask(Runnable task)
    {
        return removeFirstWaitingTask(task);
    }

    /**
     * @deprecated Use {@link #submit(Runnable)} instead.
     */
    @Deprecated
    public boolean addTask(Runnable task, boolean onEDT, int id)
    {
        return addTask(task, onEDT);
    }

    /**
     * @deprecated Use {@link #submit(Runnable)} instead.
     */
    @Deprecated
    public boolean addTask(Runnable task, boolean onEDT)
    {
        try
        {
            submit(task, onEDT);
        }
        catch (RejectedExecutionException E)
        {
            return false;
        }

        return true;
    }

    /**
     * @deprecated Use {@link #submit(Runnable)} instead.
     */
    @Deprecated
    public boolean addTask(Runnable task)
    {
        return addTask(task, false);
    }

    @Override
    public boolean remove(Runnable task)
    {
        // don't forget to remove the reference here
        if (waitingExecution == task)
            waitingExecution = null;

        return super.remove(task);
    }

    /**
     * @deprecated Use {@link #newTaskFor(Runnable, Object)} instead.
     */
    @Deprecated
    protected <T> FutureTaskAdapter<T> newTaskFor(Runnable runnable, T value, boolean onEDT)
    {
        return new FutureTaskAdapterEDT<T>(runnable, value, onEDT);
    };

    /**
     * @deprecated Use {@link #newTaskFor(Callable)} instead.
     */
    @Deprecated
    protected <T> FutureTaskAdapter<T> newTaskFor(Callable<T> callable, boolean onEDT)
    {
        return new FutureTaskAdapterEDT<T>(callable, onEDT);
    }

    /**
     * @param handledException
     *        if set to <code>true</code> then any occurring exception during the runnable
     *        processing will be catch by {@link IcyExceptionHandler}.
     * @param runnable
     *        the runnable task being wrapped
     * @param value
     *        the default value for the returned future
     * @return a <tt>RunnableFuture</tt> which when run will run the underlying runnable and which,
     *         as a <tt>Future</tt>, will yield the given value as its result and provide for
     *         cancellation of the underlying task.
     */
    protected <T> FutureTaskAdapter<T> newTaskFor(boolean handledException, Runnable runnable, T value)
    {
        return new FutureTaskAdapter<T>(runnable, value, handledException);
    };

    /**
     * @param handledException
     *        if set to <code>true</code> then any occurring exception during the runnable
     *        processing will be catch by {@link IcyExceptionHandler}.
     * @param callable
     *        the callable task being wrapped
     * @return a <tt>RunnableFuture</tt> which when run will call the
     *         underlying callable and which, as a <tt>Future</tt>, will yield
     *         the callable's result as its result and provide for
     *         cancellation of the underlying task.
     */
    protected <T> FutureTaskAdapter<T> newTaskFor(boolean handledException, Callable<T> callable)
    {
        return new FutureTaskAdapter<T>(callable, handledException);
    }

    @Override
    public void execute(Runnable task)
    {
        super.execute(task);
        // save the last executed task
        waitingExecution = task;
    }

    /**
     * Submit the given task (internal use only).
     */
    protected synchronized <T> FutureTask<T> submit(FutureTaskAdapter<T> task)
    {
        execute(task);
        return task;
    }

    @Override
    public Future<?> submit(Runnable task)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(false, task, null));
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(false, task, result));
    }

    @Override
    public <T> Future<T> submit(Callable<T> task)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(false, task));
    }

    /**
     * Submits a Runnable task for execution and returns a Future
     * representing that task. The Future's <tt>get</tt> method will
     * return <tt>null</tt> upon <em>successful</em> completion.
     * 
     * @param handleException
     *        if set to <code>true</code> then any occurring exception during the runnable
     *        processing will be catch by {@link IcyExceptionHandler}.
     * @param task
     *        the task to submit
     * @return a Future representing pending completion of the task
     * @throws RejectedExecutionException
     *         if the task cannot be
     *         scheduled for execution
     * @throws NullPointerException
     *         if the task is null
     */
    public Future<?> submit(boolean handleException, Runnable task)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(handleException, task, null));
    }

    /**
     * Submits a Runnable task for execution and returns a Future
     * representing that task. The Future's <tt>get</tt> method will
     * return the given result upon successful completion.
     * 
     * @param handleException
     *        if set to <code>true</code> then any occurring exception during the runnable
     *        processing will be catch by {@link IcyExceptionHandler}.
     * @param task
     *        the task to submit
     * @param result
     *        the result to return
     * @return a Future representing pending completion of the task
     * @throws RejectedExecutionException
     *         if the task cannot be
     *         scheduled for execution
     * @throws NullPointerException
     *         if the task is null
     */
    public <T> Future<T> submit(boolean handleException, Runnable task, T result)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(handleException, task, result));
    }

    /**
     * Submits a value-returning task for execution and returns a
     * Future representing the pending results of the task. The
     * Future's <tt>get</tt> method will return the task's result upon
     * successful completion.
     * <p>
     * If you would like to immediately block waiting for a task, you can use constructions of the form
     * <tt>result = exec.submit(aCallable).get();</tt>
     * <p>
     * Note: The {@link Executors} class includes a set of methods that can convert some other common closure-like
     * objects, for example, {@link java.security.PrivilegedAction} to {@link Callable} form so they can be submitted.
     * 
     * @param handleException
     *        if set to <code>true</code> then any occurring exception during the runnable
     *        processing will be catch by {@link IcyExceptionHandler}.
     * @param task
     *        the task to submit
     * @return a Future representing pending completion of the task
     * @throws RejectedExecutionException
     *         if the task cannot be
     *         scheduled for execution
     * @throws NullPointerException
     *         if the task is null
     */
    public <T> Future<T> submit(boolean handleException, Callable<T> task)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(handleException, task));
    }

    /**
     * @deprecated Use {@link #submit(Runnable)} instead and ThreadUtil.invokeNow(..) where you need
     *             it.
     */
    @Deprecated
    public Future<?> submit(Runnable task, boolean onEDT)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(task, null, onEDT));
    }

    /**
     * @deprecated Use {@link #submit(Runnable, Object)} instead and ThreadUtil.invokeNow(..) where
     *             you
     *             need it.
     */
    @Deprecated
    public <T> Future<T> submit(Runnable task, T result, boolean onEDT)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(task, result, onEDT));
    }

    /**
     * @deprecated Use {@link #submit(Callable)} instead and ThreadUtil.invokeNow(..) where you need
     *             it.
     */
    @Deprecated
    public <T> Future<T> submit(Callable<T> task, boolean onEDT)
    {
        if (task == null)
            throw new NullPointerException();

        return submit(newTaskFor(task, onEDT));
    }

    /**
     * Return true if one or more process are executing or we still have waiting tasks.
     */
    public boolean isProcessing()
    {
        return (getActiveCount() > 0) || hasWaitingTasks();
    }

    /**
     * Wait for all tasks completion
     */
    public void waitAll()
    {
        while (isProcessing())
            ThreadUtil.sleep(1);
    }

    /**
     * shutdown and wait current tasks completion
     */
    public void shutdownAndWait()
    {
        shutdown();
        while (!isTerminated())
            ThreadUtil.sleep(1);
    }

    /**
     * @return the priority
     */
    public int getPriority()
    {
        return priority;
    }

    /**
     * @param priority
     *        the priority to set
     */
    public void setPriority(int priority)
    {
        this.priority = priority;
    }

    /**
     * @deprecated Use {@link #getThreadName()} instead
     */
    @Deprecated
    public String getDefaultThreadName()
    {
        return ((ProcessorThreadFactory) getThreadFactory()).getName();
    }

    /**
     * @deprecated Use {@link #setThreadName(String)} instead
     */
    @Deprecated
    public void setDefaultThreadName(String defaultThreadName)
    {
        ((ProcessorThreadFactory) getThreadFactory()).setName(defaultThreadName);
    }

    /**
     * Return the thread name.
     */
    public String getThreadName()
    {
        return ((ProcessorThreadFactory) getThreadFactory()).getName();
    }

    /**
     * Set the wanted thread name.
     */
    public void setThreadName(String defaultThreadName)
    {
        ((ProcessorThreadFactory) getThreadFactory()).setName(defaultThreadName);
    }

    /**
     * Get the number of free slot in queue
     */
    public int getFreeSlotNumber()
    {
        return getQueue().remainingCapacity();
    }

    /**
     * Return true if queue is full
     */
    public boolean isFull()
    {
        return getFreeSlotNumber() == 0;
    }

    /**
     * Return waiting tasks
     */
    protected List<FutureTaskAdapter<?>> getWaitingTasks()
    {
        final BlockingQueue<Runnable> q = getQueue();
        final List<FutureTaskAdapter<?>> result = new ArrayList<FutureTaskAdapter<?>>();

        synchronized (q)
        {
            for (Runnable r : q)
                result.add((FutureTaskAdapter<?>) r);
        }

        return result;
    }

    /**
     * Return waiting tasks for the specified Runnable instance
     */
    protected List<FutureTaskAdapter<?>> getWaitingTasks(Runnable task)
    {
        final List<FutureTaskAdapter<?>> result = new ArrayList<FutureTaskAdapter<?>>();

        // scan all tasks
        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.runnable == task)
                result.add(f);

        return result;
    }

    /**
     * Return waiting tasks for the specified Callable instance
     */
    protected List<FutureTaskAdapter<?>> getWaitingTasks(Callable<?> task)
    {
        final List<FutureTaskAdapter<?>> result = new ArrayList<FutureTaskAdapter<?>>();

        // scan all tasks
        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.callable == task)
                result.add(f);

        return result;
    }

    /**
     * Return the number of waiting task
     */
    public int getWaitingTasksCount()
    {
        final int result = getQueue().size();

        // TODO : be sure that waitingExecution pass to null when task has been taken in account.
        // Queue can be empty right after a task submission.
        // For this particular case we return 1 if a task has been submitted
        // and not taken in account with a timeout of 1 second.
        if ((result == 0) && ((waitingExecution != null) && ((System.currentTimeMillis() - lastAdd) < 1000)))
            return 1;

        return result;
    }

    /**
     * @deprecated Not anymore supported.<br>
     *             Use {@link #getWaitingTasksCount(Callable)} or {@link #getWaitingTasksCount(Runnable)} instead.
     */
    @Deprecated
    public int getWaitingTasksCount(int id)
    {
        return 0;
    }

    /**
     * Return the number of task waiting in queue for the specified <tt>Runnable</tt> instance.
     */
    public int getWaitingTasksCount(Runnable task)
    {
        int result = 0;

        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.runnable == task)
                result++;

        return result;
    }

    /**
     * Return the number of task waiting in queue for the specified <tt>Callable</tt> instance.
     */
    public int getWaitingTasksCount(Callable<?> task)
    {
        int result = 0;

        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.callable == task)
                result++;

        return result;
    }

    /**
     * Return true if we have at least one task waiting in queue
     */
    public boolean hasWaitingTasks()
    {
        return (getWaitingTasksCount() > 0);
    }

    /**
     * @deprecated Not anymore supported.<br>
     *             Use {@link #hasWaitingTasks(Callable)} or {@link #hasWaitingTasks(Runnable)} instead.
     */
    @Deprecated
    public boolean hasWaitingTasks(int id)
    {
        return false;
    }

    /**
     * Return true if we have at least one task in queue for the specified <tt>Runnable</tt> instance.
     */
    public boolean hasWaitingTasks(Runnable task)
    {
        // scan all tasks
        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.runnable == task)
                return true;

        return false;
    }

    /**
     * Return true if we have at least one task in queue for the specified <tt>Callable</tt> instance.
     */
    public boolean hasWaitingTasks(Callable<?> task)
    {
        // scan all tasks
        for (FutureTaskAdapter<?> f : getWaitingTasks())
            if (f.callable == task)
                return true;

        return false;
    }

    /**
     * @deprecated Not anymore supported.<br>
     *             USe {@link #removeFirstWaitingTask(Runnable)} or {@link #removeFirstWaitingTask(Callable)} instead.
     */
    @Deprecated
    public boolean removeFirstWaitingTask(int id)
    {
        return false;
    }

    /**
     * Remove first waiting task for the specified <tt>FutureTaskAdapter</tt> instance.
     */
    protected boolean removeFirstWaitingTask(FutureTaskAdapter<?> task)
    {
        if (task == null)
            return false;

        synchronized (getQueue())
        {
            // remove first task of specified instance
            for (FutureTaskAdapter<?> f : getWaitingTasks())
                if (f == task)
                    return remove(f);
        }

        return false;
    }

    /**
     * Remove first waiting task for the specified <tt>Runnable</tt> instance.
     */
    public boolean removeFirstWaitingTask(Runnable task)
    {
        if (task == null)
            return false;

        synchronized (getQueue())
        {
            // remove first task of specified instance
            for (FutureTaskAdapter<?> f : getWaitingTasks())
                if (f.runnable == task)
                    return remove(f);
        }

        return false;
    }

    /**
     * Remove first waiting task for the specified <tt>Callable</tt> instance.
     */
    public boolean removeFirstWaitingTask(Callable<?> task)
    {
        if (task == null)
            return false;

        synchronized (getQueue())
        {
            // remove first task of specified instance
            for (FutureTaskAdapter<?> f : getWaitingTasks())
                if (f.callable == task)
                    return remove(f);
        }

        return false;
    }

    /**
     * @deprecated Not anymore supported.<br>
     *             USe {@link #removeWaitingTasks(Runnable)} or {@link #removeWaitingTasks(Callable)} instead.
     */
    @Deprecated
    public boolean removeWaitingTasks(int id)
    {
        return false;
    }

    /**
     * Remove all waiting tasks for the specified <tt>Runnable</tt> instance.
     */
    public boolean removeWaitingTasks(Runnable task)
    {
        boolean result = false;

        synchronized (getQueue())
        {
            // remove all tasks of specified instance
            for (FutureTaskAdapter<?> f : getWaitingTasks(task))
                result |= remove(f);
        }

        return result;
    }

    /**
     * Remove all waiting tasks for the specified <tt>Callable</tt> instance.
     */
    public boolean removeWaitingTasks(Callable<?> task)
    {
        boolean result = false;

        synchronized (getQueue())
        {
            // remove all tasks of specified instance
            for (FutureTaskAdapter<?> f : getWaitingTasks(task))
                result |= remove(f);
        }

        return result;
    }

    /**
     * Clear all waiting tasks
     */
    public void removeAllWaitingTasks()
    {
        waitingExecution = null;

        synchronized (getQueue())
        {
            // remove all tasks
            getQueue().clear();
        }
    }

    /**
     * @deprecated This method is useless.
     */
    @Deprecated
    public void limitWaitingTask(Runnable task, int value)
    {
        synchronized (getQueue())
        {
            final List<FutureTaskAdapter<?>> tasks = getWaitingTasks(task);
            final int numToRemove = tasks.size() - value;

            for (int i = 0; i < numToRemove; i++)
                remove(tasks.get(i));
        }
    }

    /**
     * @deprecated Not anymore supported !
     */
    @Deprecated
    public void limitWaitingTask(int id, int value)
    {
        // not anymore supported
    }

    /**
     * @deprecated This method is useless.
     */
    @Deprecated
    public boolean limitWaitingTask(int value)
    {
        synchronized (getQueue())
        {
            final List<FutureTaskAdapter<?>> tasks = getWaitingTasks();
            final int numToRemove = tasks.size() - value;

            for (int i = 0; i < numToRemove; i++)
                remove(tasks.get(i));
        }

        return false;
    }

    /**
     * @deprecated Useless...
     */
    @Deprecated
    public void addListener(ProcessorEventListener listener)
    {
        //
    }

    /**
     * @deprecated Useless...
     */
    @Deprecated
    public void removeListener(ProcessorEventListener listener)
    {
        //
    }

    /**
     * @deprecated useless
     */
    @Deprecated
    public void fireDoneEvent(FutureTaskAdapter<?> task)
    {
        //
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r)
    {
        super.beforeExecute(t, r);

        // ok we can remove reference...
        waitingExecution = null;
    }
}