package de.renew.api;

import java.io.IOException;
import java.io.ObjectInput;
import java.util.Properties;

import de.renew.application.SimulatorPlugin;
import de.renew.engine.thread.SimulationThreadPool;
import de.renew.net.NetInstance;
import de.renew.simulatorontology.simulation.SimulationRunningException;
import de.renew.util.SingletonException;

/**
 * Interface for a {@code SimulationStateLoader}.
 * Implementations of this class are responsible for loading simulation states
 * via {@link #loadState} that had been saved by {@link SimulatorPlugin#saveState}.
 */
public interface ISimulationStateLoader {
    /**
     * Restores a simulation saved by {@link SimulatorPlugin#saveState}. Reads all stored
     * {@code Net}s and {@code NetInstance}s. The result is a
     * ready-to-run simulation setup. Some net instances (those that have been
     * explicitly referenced in the {@code saveState} call) are returned so
     * they can be processed specially (e.g. open instance drawing windows).
     * <p>
     * If the given {@code ObjectInput} is a <b>
     * {@link de.renew.util.RenewObjectInputStream}</b>, the necessary steps to
     * cover delayed serialization will be made. The ObjectInputStream will be
     * read using {@code de.renew.util.ClassSource} to provide its ability
     * of reloading all user defined classes.
     * </p>
     *
     * <p>
     * This method will automatically create a new thread if it is not called
     * from a simulation thread. Contrary to the method
     * {@link de.renew.simulator.api.SimulationManager#setupSimulation}, exceptions are communicated anyway.
     * </p>
     *
     * <p>
     * The behavior of the method has changed from Renew release 2.1 to 2.2. It
     * no longer automatically terminates a running simulation. Instead, an
     * exception is thrown (see below).
     * </p>
     *
     * <p>
     * Callers of this method that switch to a simulation thread by themselves
     * should use {@link SimulationThreadPool#getNew}. This method
     * automatically discards the new thread pool if simulation setup fails.
     * After successful execution of this method, the new thread pool becomes
     * the current thread pool and the calling thread belongs to the current
     * simulation.
     * </p>
     *
     * <p>
     * Access to this method is exclusive. The Java synchronized mechanism is
     * replaced by a specialized {@link de.renew.util.Lock#lock}. How to achieve
     * synchronization across multiple methods is explained there.
     * </p>
     *
     * @param input source stream (see note about
     *        {@code RenewObjectInputStream} above).
     * @param properties additional properties that specify this simulation
     *        environment. These properties will override any default values
     *        from the plugin properties. May be {@code null}.
     * @return array of explicitly stored net instances (e.g. to be displayed to
     *         the user).
     * @throws IOException if an error occurs during reading the input stream
     * @throws ClassNotFoundException if an unknown object type was included in the state
     * @throws SimulationRunningException if a simulation is already running.
     */
    NetInstance[] loadState(final ObjectInput input, Properties properties)
        throws IOException, ClassNotFoundException, SingletonException, SimulationRunningException;
}
