package de.renew.engine.simulator;

import de.renew.engine.searcher.Finder;
import de.renew.engine.searcher.Searcher;
import de.renew.engine.thread.SimulationThreadPool;
import de.renew.simulatorontology.simulation.StepIdentifier;

/**
 * A {@link Finder} that executes a {@link Searcher} in the simulation thread.
 * It can be used to execute a {@link Searcher} in the simulation thread
 * and wait for its completion.
 * Note that an instance of this class can only be used once.
 */
public class ExecuteFinder implements Finder {
    private Binding _binding;

    /**
     * Creates a new {@link ExecuteFinder}.
     * This constructor can only be called in a simulation thread.
     *
     * @throws AssertionError if this constructor is called not in a simulation thread
     */
    public ExecuteFinder() {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
    }

    @Override
    public void found(Searcher searcher) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        if (_binding != null) {
            throw new RuntimeException("ExecuteFinder was reused.");
        }
        _binding = new Binding(searcher);
    }

    @Override
    public boolean isCompleted() {
        return _binding != null;
    }

    /**
     * Executes the {@link Searcher} that was found by this {@link Finder}.
     * This method can only be called once.
     *
     * @param stepIdentifier the {@link StepIdentifier} to execute the {@link Searcher} in
     * @param asynchronous whether the execution should be asynchronous
     * @return true if the execution was successful, false otherwise
     * @throws AssertionError if this method is called not in a simulation thread
     * @throws RuntimeException if this method is called more than once or if no {@link Searcher} was found
     */
    public boolean execute(final StepIdentifier stepIdentifier, final boolean asynchronous) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        boolean result = _binding.execute(stepIdentifier, asynchronous);
        _binding = null;
        return result;

    }
}