package de.renew.shadowcompiler;

import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.ShadowNetSystem;
import de.renew.simulatorontology.shadow.SyntaxException;

/**
 * A {@code IShadowNetSystemCompiler} is used to compile a {@link ShadowNetSystem}.
 */
public interface IShadowNetSystemCompiler {

    /**
     * Creates a {@code ShadowCompiler} for the given {@code ShadowNet} that wil use the given {@code ShadowLookup}.
     *
     * @param lookup the {@code ShadowLookup} that the created compiler will use
     * @param net the {@code ShadowNet} for which the compiler should be created
     * @return the created {@code ShadowCompiler}
     * @throws SyntaxException if no compiler for the net has been set
     */
    ShadowCompiler createShadowNetCompiler(ShadowLookup lookup, ShadowNet net)
        throws SyntaxException;

    /**
     * Sets the default {@code ShadowCompilerFactory} that should be used to compile the given {@code ShadowNetSystem}.
     *
     * @param compilerFactory the {@code ShadowCompilerFactory} to use for compilation
     * @param netSystem the {@code ShadowNetSystem} the given compiler should compile when {@link #compile(ShadowNetSystem)}} is called.
     */
    void setDefaultCompilerFactory(
        ShadowCompilerFactory compilerFactory, ShadowNetSystem netSystem);

    /**
     * Sets the default {@code ShadowCompilerFactory} that should be used to compile the given {@code ShadowNet}. This means, that during compilation this net will use the given compiler
     * and not use the default compiler specified for the corresponding {@code ShadowNetSystem}. If the given compiler is {@code null}, the default compiler is used.
    
     * @param compilerFactory the {@code ShadowCompilerFactory} to use for compilation, or {@code null} to use the default compiler
     * @param shadowNet the {@code ShadowNetSystem} the given compiler should compile when {@link #compile(ShadowNetSystem)}} on the corresponding {@code ShadowNetSystem} is called.
     */
    void setCompilerFactory(ShadowCompilerFactory compilerFactory, ShadowNet shadowNet);

    /**
     * Creates a new {@code InscriptionValidator} that may be used to validate the inscriptions of the given {@code ShadowNet}.
     *
     * @param net the net whose inscriptions should be validated
     * @return a new {@code InscriptionValidator}
     */
    InscriptionValidator createInscriptionValidator(ShadowNet net);

    /**
     * Inserts this shadow net into another shadow net system. This
     * immediately implies removal from the previous net system.
     * If the old and the new net system use different compilers, the
     * net-specific compiler attribute is modified to retain the compiler
     * assigment for the net.
     * <p>
     * This method should not be executed after compilation of the
     * shadow net: The results and relations to the compiled net
     * and other shadow nets of the previous net system are not
     * defined.
     * </p>
     *
     * @param shadowNet the {@code ShadowNet} that should be moved
     * @param shadowNetSystem the new shadow net system this net should be switched to
     */
    void switchNetSystem(ShadowNet shadowNet, ShadowNetSystem shadowNetSystem);

    /**
     * Compiles the given {@code ShadowNetSystem} by compiling all contained {@link ShadowNet} instances
     * using their respective {@link ShadowCompiler}.
     *
     * @param shadowNetSystem the {@code ShadowNetSystem} to compile
     * @return a {@code ShadowLookup} mapping all shadow net elements to their corresponding compiled version
     * @throws SyntaxException if the given net system contains an invalid syntax
     */
    ShadowLookup compile(ShadowNetSystem shadowNetSystem) throws SyntaxException;

    /**
     * Compiles the given {@code ShadowNetSystem} by compiling all contained {@link ShadowNet} instances
     * that have not yet been compiled and made known to the simulator using their respective {@link ShadowCompiler}.
     *
     * @param shadowNetSystem the {@code ShadowNetSystem} to compile
     * @return a {@code ShadowLookup} mapping all shadow net elements to their corresponding compiled version
     * @throws SyntaxException if the given net system contains an invalid syntax
     */
    ShadowLookup compileMore(ShadowNetSystem shadowNetSystem) throws SyntaxException;
}
