package de.renew.util;

import java.util.LinkedList;


/**
 * A <code>RunQueue</code> is responsible for executing
 * <code>Runnable</code> objects in a separate thread fifo-style.
 * The thread is never stopped until it is interrupted. When
 * interrupted, all pending events are discarded.
 *
 * @author <a href="mailto:kummer@informatik.uni-hamburg.de">Olaf Kummer</a>
 */
public class RunQueue implements Runnable {
    private final LinkedList<Runnable> _runnables;
    private boolean _terminated = false;

    /**
     *  Starts the execution of runnable objects in the Queue
     */
    public RunQueue() {
        _runnables = new LinkedList<>();
    }

    /**
     *  states if the queue terminated
     * @return a boolean which is true if the queue is terminated and false else
     */
    public boolean isTerminated() {
        return _terminated;
    }

    /**
     * Enqueues the given event.
     * <p>
     * If queue has been terminated, events that arrive are discarded
     * immediately and silently.
     *
     * @param runnable The runnable object to add.
     */
    public synchronized void add(Runnable runnable) {
        if (!_terminated) {
            _runnables.addFirst(runnable);
            notify();
        }
    }

    @Override
    public void run() {
        Runnable runnable;
        while (!_terminated) {
            synchronized (this) {
                if (Thread.currentThread().isInterrupted()) {
                    _terminated = true;
                } else if (_runnables.isEmpty()) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        _terminated = true;
                    }
                } else {
                    runnable = _runnables.removeLast();
                    runnable.run();
                }
            }
        }
    }
}