package de.renew.engine.thread;

import de.renew.util.Semaphor;


/**
 * This class serves as a way to run a {@link Runnable} in a simulation thread
 * and to wait for its {@link Runnable#run()} method to finish. Furthermore,
 * this class enables the advanced locking scheme of
 * {@link InheritableSimulationThreadLock} by storing a reference to the calling
 * thread that can be queried via {@link #getAncestor()}.
 * <p>
 * The <code>BlockingSimulationRunnable</code> stores a reference to its
 * creating ancestor thread for later use in the executing
 * {@link SimulationThread} and provides a {@link Semaphor} that allows the
 * {@link SimulationThreadPool#executeAndWait(Runnable)}
 * implementation to block the calling thread.
 * </p>
 * <p>
 * Upon task completion, <code>BlockingSimulationRunnable</code> frees the
 * {@link Semaphor} and cleans the ancestor reference from the executing
 * {@link SimulationThread}. In presence of exceptions, the cleanup can be
 * requested externally through {@link #abort(SimulationThread)}.
 * </p>
 *
 * @author Benjamin Schleinzer
 * @author Michael Duvigneau
 */
class BlockingSimulationRunnable implements Runnable {

    /**
     * The Runnable that should be run
     */
    private final Runnable _task;

    /**
     * The semaphore that should be notified if the thread has run successfully
     */
    private final Semaphor _lock;

    /**
     * The thread that placed the order for this Runnable
     */
    private Thread _ancestor;

    /**
     * Create an instance of a
     * <code>BlockingSimulationRunnable</code> with a {@link Runnable}
     * to run and a {@link Semaphor} that blocks the calling thread.
     *
     * @param task the task to run
     * @param lock the semaphore that gets notified after execution finished
     * @param ancestor the calling thread (the ancestor)
     */
    BlockingSimulationRunnable(Runnable task, Semaphor lock, Thread ancestor) {
        _task = task;
        _lock = lock;
        _ancestor = ancestor;
    }

    /**
     * Retrieve the reference to the calling thread.
     * @return  the calling thread
     */
    Thread getAncestor() {
        return _ancestor;
    }

    /**
     * {@inheritDoc}
     * <p>
     * <code>BlockingSimulationRunnable</code> just delegates execution to the
     * nested {@link Runnable}.  After execution, it additionally frees the
     * calling thread (ancestor) and cleans the ancestor reference in the
     * executing {@link SimulationThread}.
     * </p>
     * <p>
     * This method should be called by the Executor only since the executor
     * locks the semaphore.
     * </p>
     */
    @Override
    public void run() {
        try {
            _task.run();
        } finally {
            abort((SimulationThread) Thread.currentThread());
        }
    }

    /**
     * Frees the calling thread (ancestor) and cleans the respective reference
     * in the executing {@link SimulationThread}.  This method should be called
     * if something goes wrong during execution to ensure continuation of the
     * calling thread.
     *
     * @param t the executing thread whose ancestor information should be
     *            cleaned.  If <code>null</code>, cleaning is skipped.
     */
    void abort(SimulationThread t) {
        _lock.V();
        _ancestor = null;
        if (t != null) {
            t.setAncestor(null);
        }
    }
}