package de.renew.plugin.jpms;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * This exception is thrown by the module manager when it fails to load
 * modules due to conflicts in the loading order.
 */
public class ModuleLayerCreationException extends RuntimeException {
    /**
     * A constructor for the ModuleLayerCreationException.
     * Creates an exception message when more than one module is included in a layer
     * @param modulesToLoad A string with the loaded module's descriptor
     * @param loadedModules A collection of modules that were added to the layer that caused the exception.
     */
    public ModuleLayerCreationException(
        Set<String> modulesToLoad, Collection<Module> loadedModules)
    {
        super(
            "While loading the modules " + stringRepresentation(modulesToLoad) + ", "
                + "the Java Module System attempted to include one or more different modules in the same layer. "
                + "This is usually the result of an incorrect loading order of plugins. "
                + "The following modules were included in this layer: "
                + stringRepresentation(loadedModules) + ". "
                + "Please make sure that the additional modules are loaded before "
                + stringRepresentation(modulesToLoad) + ".");
    }

    /**
     * A constructor for the ModuleLayerCreationException.
     * Creates an exception if parent layers are not located during Module load.
     * @param modulesToLoad The Modules that were attempted to load
     * @param requiredLayers A String collection containing names of required parent layers to load the Module
     * @param foundLayers A Module Collection of parent layers that were located during Module load
     */
    public ModuleLayerCreationException(
        Set<String> modulesToLoad, Collection<String> requiredLayers,
        Collection<ModuleLayer> foundLayers)
    {
        super(
            "Couldn't find all of the required parent layers for modules "
                + stringRepresentation(modulesToLoad) + ". " + "Required parent layers: "
                + stringRepresentation(requiredLayers) + ". " + "Found layers: "
                + stringRepresentation(foundLayers) + ". "
                + "This is usually the result of an incorrect loading order of plugins. "
                + "Please make sure that all required modules are loaded before "
                + stringRepresentation(modulesToLoad) + ".");
    }

    private static String stringRepresentation(Collection<?> items) {
        return items.stream().map(ModuleLayerCreationException::stringRepresentation)
            .collect(Collectors.joining(", "));
    }

    private static String stringRepresentation(Object item) {
        if (item instanceof Module m) {
            return m.getName();
        } else {
            return item.toString();
        }
    }
}
