package de.renew.plugin.jpms;

import java.util.List;


/**
 * A  layer  of  a single component in the module  management  of  Renew.  Each
 * component  is  named  and is backed by a module  layer  with  an  associated
 * controller obj. The root of Renews component graph is the {@link #BOOT boot}
 * layer.
 *
 * @author Kjell Ehlers
 * @since Renew 4.2
 */
public interface ComponentLayer {

    /**
     * Returns the component's name. The name must be unique and non-null.
     *
     * @return The component's name
     */
    String getName();

    /**
     * Returns the controller obj that governs this component's module layer.
     *
     * @return The controller obj
     */
    ModuleLayer.Controller getController();

    /**
     * Returns an unmodifiable list of this component's parents, in no specific
     * order.  If  this is the {@link #BOOT boot layer} then an empty  list  is
     * returned.
     *
     * @return A possibly-empty unmodifiable list of this component's parents
     */
    List<ComponentLayer> parents();

    /**
     * Returns  the  module layer associated with this component.  The  default
     * implementation guarantees that the following holds:
     * <blockquote><pre>
     *     ComponentLayer component = ...;
     *     ModuleLayer a = component.getLayer();
     *     ModuleLayer b = component.getController().layer();
     *
     *     a.equals(b); // true
     * </pre></blockquote>
     *
     * @return The module layer
     */
    default ModuleLayer getLayer() {
        return getController().layer();
    }

    /**
     * The boot layer component, which is backed by  {@link ModuleLayer#boot()}
     * and  contains  at least {@code de.renew.loader}. It has no  parents  and
     * access to its controller obj is not permitted.
     */
    ComponentLayer BOOT = new ComponentLayer() {
        @Override
        public String getName() {
            return "Boot layer";
        }

        @Override
        public ModuleLayer.Controller getController() {
            throw new UnsupportedOperationException(
                "Access of boot layer controller is not permitted");
        }

        @Override
        public List<ComponentLayer> parents() {
            return List.of();
        }

        @Override
        public ModuleLayer getLayer() {
            return ModuleLayer.boot();
        }

        @Override
        public String toString() {
            return getName();
        }
    };
}
