package de.renew.net;

import java.io.Serializable;

import de.renew.engine.common.SimulatorEventLogger;
import de.renew.engine.events.NetInstantiationException;
import de.renew.engine.thread.SimulationThreadPool;
import de.renew.simulator.api.SimulationManager;
import de.renew.simulatorontology.simulation.StepIdentifier;
import de.renew.unify.Impossible;

/**
 * {@code NetInstantiator} is the default implementation of {@code INetInstantiator}. It creates instances of the net
 * that is passed as an argument to its constructor.
 */
public class NetInstantiator implements INetInstantiator, Serializable {
    /**
     * The net that this {@code NetInstantiator} creates instances of.
     */
    private final Net _net;

    /**
     * Creates a new {@code NetInstantiator} that creates instances of the given net.
     *
     * @param net the net that the {@code NetInstantiator} should create instances of
     */
    public NetInstantiator(Net net) {
        _net = net;
    }

    /**
     * Returns the net that this {@code NetInstantiator} creates instances of.
     *
     * @return the net that this {@code NetInstantiator} creates instances of
     */
    protected Net getNet() {
        return _net;
    }

    @Override
    public NetInstance makeInstance() throws Impossible {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        // Instead of creating a generic NetInstance, we might also
        // want to create a specialized NetInstance that supports
        // own methods and implements interfaces.
        return new NetInstanceImpl(_net);
    }

    @Override
    public NetInstance buildInstance(StepIdentifier stepIdentifier) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        try {
            NetInstance instance = makeInstance();

            instance.createConfirmation(stepIdentifier);
            return instance;
        } catch (Impossible e) {
            RuntimeException re =
                new RuntimeException("Could not make instance of net " + _net.getName() + ".", e);
            SimulatorEventLogger.log(stepIdentifier, new NetInstantiationException(_net, e));
            throw re;
        }
    }

    @Override
    public NetInstance buildInstance() {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        return buildInstance(SimulationManager.getCurrentSimulator().currentStepIdentifier());
    }

}
