package de.renew.engine.simulator;

import org.junit.Ignore;
import org.junit.jupiter.api.BeforeEach;

import de.renew.engine.thread.SimulationThreadPool;

import static org.junit.jupiter.api.Assertions.assertTrue;


/**
 * Tests for deadlock bug #3616.
 *
 * @author Michael Simon
 */
public class ConcurrentSimulatorTest {
    private boolean _finished = false;
    private ConcurrentSimulator _simulator;
    private Thread _simulatorThread;

    /**
     * Setup method to initialize this test environment.
     */
    @BeforeEach
    public void setUp() {
        _simulator = new ConcurrentSimulator(true);
        _simulator.step();
        System.out.println("Set up");
    }

    /**
     * Tests whether race conditions can occur when using the methods
     * {@link ConcurrentSimulator#startRun} and {@link ConcurrentSimulator#terminateRun}.
     * <p>
     * Deprecated for now because creating a {@link ConcurrentSimulator} throws
     * an exception since this thread is not in a simulation thread.
     *
     * @throws InterruptedException if race conditions occur and any thread
     *                              interrupts the currently active thread
     *                              while it is sleeping
     */
    @SuppressWarnings("deprecation")
    @Ignore
    public void testRunTerminateRaceCondition() throws InterruptedException {
        //TODO Check this test
        // Find the simulator thread.
        SimulationThreadPool.getCurrent().executeAndWait(() -> {
            Thread[] list = new Thread[1];

            // Find thread group of the simulator thread.
            ThreadGroup group = Thread.currentThread().getThreadGroup();

            // Find the simulator thread.
            group.enumerate(list);
            _simulatorThread = list[0];
        });

        // Suspend the simulator thread.
        // At this point, the simulator thread is in the AbstractConcurrentSimulator.run() method
        // waiting for desiredMode to change near the end of the outermost while loop.
        _simulatorThread.suspend();

        // Issue run request.
        _simulator.startRun();
        // Wait for the run request to be processed.
        Thread.sleep(10);

        // Issue termination request in a concurrent thread.
        SimulationThreadPool.getCurrent().execute(() -> {
            _simulator.terminateRun();
            _finished = true;
        });
        // Wait the termination request to reach the point where it is waiting on AbstractConcurrentSimulator.idle.
        Thread.sleep(10);

        // Resume the simulator thread.
        _simulatorThread.resume();
        // Wait for the simulator thread to exit the AbstractConcurrentSimulator.run() method.
        Thread.sleep(10);

        // Now both the simulator thread and the termination request should be finished.
        assertTrue(_finished);
    }
}