package de.renew.net.inscription.transition;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import de.renew.engine.searcher.Binder;
import de.renew.engine.searcher.Executable;
import de.renew.engine.searcher.Occurrence;
import de.renew.engine.searcher.OccurrenceDescription;
import de.renew.engine.searcher.Searcher;
import de.renew.engine.searcher.VariableMapperCopier;
import de.renew.engine.thread.SimulationThreadPool;
import de.renew.net.TransitionInstance;
import de.renew.net.inscription.AbstractOccurrence;
import de.renew.unify.Impossible;


/**
 * The base class for occurrences that derive their semantics from
 * a number of other occurrences.
 */
public class CompositeOccurrence extends AbstractOccurrence {
    private final List<Occurrence> _occurrences = new ArrayList<>();

    /**
     * Initializes an occurrence for a given {@link TransitionInstance}
     * and checks if the {@link SimulationThreadPool} is a {@link SimulationThread}.
     *
     * @param tInstance the given {@link TransitionInstance}
     */
    public CompositeOccurrence(TransitionInstance transitionInstance) {
        super(transitionInstance);
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
    }

    /**
     * Adds another {@link Occurrence} to the {@code occurrences},
     * if the {@link SimulationThreadPool} is a {@link SimulationThread}.
     *
     * @param occurrence the {@link Occurrence}, which has to be added to the {@code occurrences}
     */
    public void addOccurrence(Occurrence occurrence) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        _occurrences.add(occurrence);
    }

    /**
     * Adds a {@link Collection} of {@link Occurrence}s to the {@code occurrences},
     * if the {@link SimulationThreadPool} is a {@link SimulationThread}.
     *
     * @param newOccurrences the {@link Collection} of {@link Occurrence}s,
     *                       which has to be added to the {@code occurrences}
     */
    public void addOccurrences(Collection<Occurrence> newOccurrences) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        _occurrences.addAll(newOccurrences);
    }

    @Override
    public Collection<Binder> makeBinders(Searcher searcher) throws Impossible {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        List<Binder> binders = new ArrayList<>();
        for (Occurrence occurrence : _occurrences) {
            binders.addAll(occurrence.makeBinders(searcher));
        }
        return binders;
    }

    @Override
    public Collection<Executable> makeExecutables(VariableMapperCopier variableMapperCopier) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        List<Executable> executables = new ArrayList<>();
        for (Occurrence occurrence : _occurrences) {
            executables.addAll(occurrence.makeExecutables(variableMapperCopier));
        }
        return executables;
    }

    @Override
    public OccurrenceDescription makeOccurrenceDescription(
        VariableMapperCopier variableMapperCopier)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        return null;
    }
}