package de.renew.net;

import java.util.Collection;

import de.renew.net.loading.NetLoader;
import de.renew.simulator.api.SimulationLockExecutor;
import de.renew.simulatorontology.loading.NetNotFoundException;

/**
 * An {@code INetLookup} is used to make {@link Net} instances known to the compiler.
 */
public interface INetLookup {

    /**
     * Returns the {@code Net} object with the given name.
     * If the {@code Net} is not known, the net loader is used (see
     * {@link #setNetLoader}) to load the net.
     *
     * <p>
     * This method includes a convenience wrapper so that it may be called from outside a simulation thread.
     * </p>
     *
     * @param name  the name of the net to find
     *
     * @return the {@code Net} object with the given name, never {@code null}
     *
     * @throws NetNotFoundException
     *   if the net is not loaded and no loader was set or the
     *   loader could not find the net.
     **/
    Net findForName(String name) throws NetNotFoundException;

    /**
     * Forgets all known {@code Net} instances so that they cannot be found by {@link #findForName(String)}.
     * <p>
     * This method is mutually exclusive with all operations of the
     * {@link SimulationLockExecutor#lock()} facade
     * </p>
     **/
    void forgetAllNets();

    /**
     * Returns an unmodifiable collection of all known nets. Therefore, all later changes
     * made by other threads will not be included.
     *
     * @return an unmodifiable collection over all currently known
     *         {@code Net} objects.
     **/
    Collection<Net> getAllKnownNets();

    /**
     * Returns whether a net with the given name is known at the moment.
     * This method will not trigger the net loading mechanism.
     *
     * @param name  the net's name
     * @return  {@code true} if the net has been announced as known net
     *          in the current simulation or {@code false}, otherwise.
     **/
    boolean isKnownNet(String name);

    /**
     * Confirms the end of the construction phase of the net. The
     * net made known and can be found using {@link #findForName(String)}.
     * <p>
     * This method is mutually exclusive with all operations of the
     * {@link SimulationLockExecutor#lock()} facade.
     * </p>
     *
     * @since Renew 1.6
     **/
    void makeNetKnown(Net net);

    /**
     * Makes all the given {@code Net} instances known so that they can be found using {@link #findForName(String)}.
     * <p>
     * This method is mutually exclusive with all operations of the
     * {@link SimulationLockExecutor#lock()} facade
     * </p>
     *
     * @param nets a {@code Collection} of {@code Net} instances that should be made known
     */
    void makeNetsKnown(Collection<Net> nets);

    /**
     * Sets the net loader. This request will be denied when there
     * are any known nets. You are safe if you call it immediately
     * after {@link #forgetAllNets}...
     * <p>
     * This method is mutually exclusive with all operations of the
     * {@link SimulationLockExecutor#lock()} facade
     *
     * @param netLoader the net loader to use
     * @throws IllegalStateException if there are known nets
     **/
    void setNetLoader(NetLoader netLoader);

    /**
     * Returns the current {@code NetLoader}.
     *
     * @return the current {@code NetLoader}
     **/
    NetLoader getNetLoader();
}
