package de.renew.shadowcompiler;

import de.renew.net.Net;
import de.renew.net.loading.NetLoader;
import de.renew.simulatorontology.loading.NetNotFoundException;
import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.ShadowNetLoader;
import de.renew.simulatorontology.shadow.ShadowNetSystem;
import de.renew.simulatorontology.shadow.SyntaxException;

/**
 * A net loader that provides a net by asking the shadow net loader
 * for a shadow net and then creating an empty net from it.
 */
class LoopbackNetLoader implements NetLoader {
    private final ShadowLookup _lookup;
    private final ShadowNetSystem _shadowNetSystem;
    private final ShadowNetLoader _shadowNetLoader;

    /**
     * Creates a new loopback net loader that uses the given {@link ShadowNetSystem}
     * and lookup.
     *
     * @param shadowNetSystem the shadow net system to use
     * @param lookup          the lookup to use for storing the loaded net
     */
    LoopbackNetLoader(ShadowNetSystem shadowNetSystem, ShadowLookup lookup) {
        _lookup = lookup;
        _shadowNetSystem = shadowNetSystem;
        _shadowNetLoader = shadowNetSystem.getNetLoader();
    }

    @Override
    public Net loadNet(String netName) throws NetNotFoundException {
        return appendNet(_lookup, netName);
    }

    /**
     * Asks the shadow net loader to provide a net for the given
     * name and creates an empty net if there was a shadow net.
     **/
    private Net appendNet(ShadowLookup lookup, String name) throws NetNotFoundException {
        if (_shadowNetLoader != null) {
            ShadowNet shadowNet = _shadowNetLoader.loadShadowNet(name, _shadowNetSystem);
            if (!shadowNet.getName().equals(name)) {
                throw new NetNotFoundException(
                    name + " (ShadowNetLoader provided " + shadowNet.getName() + " instead)");
            }
            Net net;
            try {
                net = ShadowNetSystemCompiler.getInstance()
                    .createShadowNetCompiler(lookup, shadowNet).createNet(shadowNet.getName());
            } catch (SyntaxException e) {
                throw new NetNotFoundException(e);
            }
            lookup.setNet(shadowNet.getName(), net);
            return net;
        } else {
            throw new NetNotFoundException(name);
        }
    }
}