/*
 * Java
 *
 * 2013-2022 ESR - Not subject to Copyright.
 *
 * This document has been released and published by E-S-R consortium, a non-profit entity.
 * To learn more about E-S-R consortium, please visit http://www.e-s-r.net/.
 * The matter contained in this document is not subject to copyright; you are free to use it for any purpose, for more information see E-S-R consortium policies.
 */
package ej.kf;

import java.io.IOException;
import java.io.InputStream;

import ej.annotation.Nullable;
import ej.kf.Feature.State;


/**
 * The Kernel represents the atomic part of an application. Kernel code is assumed to be reliable.
 * The {@link Kernel} class provides core methods to manage Features. It is intended to be used only by the Kernel code,
 * and not viewed from the Feature.
 */
public class Kernel extends Module{

	private Kernel(){
		throw new RuntimeException(); // not in API
	}

	/**
	 * Returns the singleton instance representing the Kernel.
	 * @return the singleton instance representing the Kernel
	 */
	public static Kernel getInstance(){
		throw new RuntimeException();
	}

	/**
	 * Installs a Feature from an {@link InputStream} and starts it.
	 * @param is the input stream from where the Feature data is loaded.
	 * @return the loaded Feature, in the {@link State#STARTED} state.
	 * @throws IOException if something occurs when reading {@link InputStream}
	 * @throws AlreadyLoadedFeatureException if Feature is already loaded
	 * @throws IncompatibleFeatureException if Feature is not compatible with the current Kernel
	 * @throws InvalidFormatException if Feature content is invalid
	 * @see #install(InputStream)
	 * @see Feature#start()
	 */
	public static Feature load(InputStream is) throws IOException, InvalidFormatException, IncompatibleFeatureException, AlreadyLoadedFeatureException{
		throw new RuntimeException();
	}

	/**
	 * Installs a Feature from an {@link InputStream}. Feature shall have been generated against the current Kernel classes.
	 * Feature data is read and linked to the Kernel.
	 * The Feature is added to the list of loaded features and its state is set to {@link State#INSTALLED}.
	 * The given input stream is let open.
	 * @param is the input stream from where the Feature data is loaded.
	 * @return the loaded Feature, in the {@link State#INSTALLED} state.
	 * @throws IOException if something occurs when reading {@link InputStream}
	 * @throws AlreadyLoadedFeatureException if Feature is already loaded
	 * @throws IncompatibleFeatureException if Feature is not compatible with the current Kernel
	 * @throws InvalidFormatException if Feature content is invalid
	 * @see #getAllLoadedFeatures()
	 */
	public static Feature install(InputStream is) throws IOException, InvalidFormatException, IncompatibleFeatureException, AlreadyLoadedFeatureException{
		throw new RuntimeException();
	}

	/**
	 * Uninstalls a Feature. When this method returns, the Feature code has been unlinked from the Kernel and reclaimed.
	 * The Feature is removed from the list of loaded features and its state is set to {@link State#UNINSTALLED}.
	 * @param f the feature to be uninstalled.
	 * @throws IllegalStateException if Feature state is not {@link State#INSTALLED}
	 * @see #getAllLoadedFeatures()
	 */
	public static void uninstall(Feature f){
		throw new RuntimeException();
	}

	/**
	 * Tells whether the given Feature can be uninstalled.
	 *
	 * @param f
	 *            the Feature to test
	 * @return <code>true</code> if the Feature can be uninstalled,
	 *         <code>false</code> otherwise.
	 * @since 1.6
	 */
	public static boolean canUninstall(Feature f){
		throw new RuntimeException();
	}

	/**
	 * Stops a Feature and uninstalls it if its state is {@link State#INSTALLED} after {@link Feature#stop()}.
	 * @param f the feature to be unloaded.
	 * @return <code>true</code> if Feature state is {@link State#UNINSTALLED}, <code>false</code> otherwise.
	 * @throws UnknownFeatureException if the given Feature is unknown.
	 * @throws IllegalStateException if Feature state is {@link State#UNINSTALLED}
	 * @see #uninstall(Feature)
	 * @see Feature#stop()
	 */
	public static boolean unload(Feature f) throws UnknownFeatureException{
		throw new RuntimeException();
	}

	/**
	 * Returns the set of Features currently loaded.
	 * @return all Features that are not in the state {@link State#UNINSTALLED}.
	 */
	public static Feature[] getAllLoadedFeatures(){
		throw new RuntimeException();
	}

	/**
	 * Enters in Kernel mode: the current thread context is switched to be owned by the Kernel.
	 * If the current context was already in Kernel mode, this method does nothing.
	 * <p>
	 * The context owner is automatically restored when returning from the method (equivalent to calling {@link #exit()} before returning).
	 * @see #exit()
	 */
	public static void enter(){
		throw new RuntimeException();
	}

	/**
	 * Exits from Kernel mode: the current thread context is restored to the owner of the caller of the method (which can remain the Kernel).
	 * If the restored context is owned by a Feature, all the locals that refer to an object owned by another Feature are reset to <code>null</code>.
	 * @see #enter()
	 */
	public static void exit(){
		throw new RuntimeException();
	}

	/**
	 * Tells whether the current thread context is currently in Kernel mode.
	 * @return the result of <code>Kernel.getContextOwner() == Kernel.getInstance()</code>
	 */
	public static boolean isInKernelMode(){
		throw new RuntimeException();
	}

	/**
	 * Returns the owner of the given {@link Object}.
	 * @param o the object.
	 * @return the owner of the object.
	 */
	public static Module getOwner(Object o){
		throw new RuntimeException();
	}

	/**
	 * Returns the owner of the current thread context.
	 * @return the context owner.
	 */
	public static Module getContextOwner(){
		throw new RuntimeException();
	}

	/**
	 * Sets the handler invoked when a Feature thread abruptly terminates due to an uncaught exception.
	 * @param handler the handler to register, or <code>null</code> if no explicit handler.
	 * @deprecated Use {@link Thread#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)}
	 */
	@Deprecated
	public static void setUncaughtExceptionHandler(@Nullable UncaughtExceptionHandler handler) {
		throw new RuntimeException();
	}

	/**
	 * Adds the given {@link FeatureStateListener} to the list of listeners
	 * that are notified when the state of a Feature has changed.
	 * @param listener the new listener to add
	 * @throws NullPointerException if listener is <code>null</code>
	 */
	public static void addFeatureStateListener(FeatureStateListener listener) {
		throw new RuntimeException();
	}

	/**
	 * Adds the given {@link ResourceControlListener} to the list of listeners
	 * that are notified when a Feature is stopped by the Resource Control Manager.
	 * @param listener the new listener to add
	 * @throws NullPointerException if listener is <code>null</code>
	 */
	public static void addResourceControlListener(ResourceControlListener listener){
		throw new RuntimeException();
	}

	/**
	 * Removes the {@link FeatureStateListener} to the list of listeners
	 * that are notified when the state of a Feature has changed.
	 * <p>
	 * Does nothing if the listener is not registered or <code>null</code>.
	 * @param listener the listener to be removed
	 */
	public static void removeFeatureStateListener(FeatureStateListener listener){
		throw new RuntimeException();
	}

	/**
	 * Removes the {@link ResourceControlListener} to the list of listeners
	 * that are notified when a Feature is stopped by the Resource Control Manager.
	 * <p>
	 * Does nothing if the listener is not registered or <code>null</code>.
	 * @param listener the listener to be removed
	 */
	public static void removeResourceControlListener(ResourceControlListener listener){
		throw new RuntimeException();
	}

	/**
	 * Returns an array containing all the {@link FeatureStateListener} that
	 * are notified when the state of a Feature has changed.
	 * @return an array of <code>FeatureStateListener[]</code> with all the listeners
	 */
	public static FeatureStateListener[] getAllFeatureStateListeners(){
		throw new RuntimeException();
	}

	/**
	 * Calls the {@link Runnable#run()} method with current context set to the given {@link Module}.
	 * @param contextOwner the context owner that will execute the method
	 * @param runnable the {@link Runnable} instance to run under the given {@link Feature} context.
	 * @throws IllegalAccessError if the {@link Runnable} instance is not accessible to the context owner, or if the {@link Runnable} is owned by a Feature and must run in Kernel context.
	 * @throws IllegalStateException if <code>contextOwner</code> is a Feature and not in the {@link State#STARTED} state.
	 */
	public static void runUnderContext(Module contextOwner, Runnable runnable){
		throw new RuntimeException();
	}

	/**
	 * Creates and returns a copy of the given object, so that the newly created object is owned by the given {@link Module}.
	 * The source object class must be {@link String} or must implement {@link Cloneable}. Otherwise, a {@link CloneNotSupportedException} is thrown.
	 * If the source object owner and the target owner are the same, this method is equivalent to {@link Object#clone()} method
	 * applied on the source object.
	 * Otherwise, the object can be cloned if the source object class is owned by the Kernel and all its object references are accessible to the new owner.
	 * In all other cases, an {@link IllegalAccessError} is thrown.
	 * @param from the object to clone
	 * @param toOwner the owner of the cloned object
	 * @param <T> the Kernel type of the object to clone
	 * @return the cloned object
	 * @throws CloneNotSupportedException if the source object cannot be cloned
	 * @throws IllegalAccessError if the creation of the new object would break access rules
	 * @throws IllegalStateException if <code>toOwner</code> is a Feature and not in the {@link State#STARTED} state.
	 * @throws NullPointerException if one of the arguments is <code>null</code>
	 */
	public static <T> T clone(T from, Module toOwner) throws CloneNotSupportedException {
		throw new RuntimeException();
	}

	/**
	 * Adds the {@link Converter} to the list of converters.
	 * Registered converters are used by {@link Kernel#bind(Object, Class, Feature)}.
	 * @param converter the new converter to add
	 * @throws NullPointerException if converter is <code>null</code>
	 * @throws IllegalArgumentException if a converter managing the same type is already registered
	 * @see Converter#getType()
	 */
	public static void addConverter(Converter<?> converter){
		throw new RuntimeException();
	}

	/**
	 * Removes the {@link Converter} to the list of converters.
	 * <p>
	 * Does nothing if the converter is not registered or <code>null</code>.
	 * @param converter the converter to be removed
	 */
	public static void removeConverter(Converter<?> converter){
		throw new RuntimeException();
	}

	/**
	 * <p>Binds an {@link Object} owned by a Feature to another Feature.</p>
	 * <p>
	 * When the target type is owned by the Kernel, the object is converted using the most accurate registered converter.
	 * </p>
	 * <p>
	 * When the target type is owned by the Feature, it must be a shared interface.
	 * In this case, a {@link Proxy} instance is returned.
	 * {@link Object} identity is preserved across Features: calling multiple times this method with the same parameters returns the same object.
	 * </p>
	 * @param o the object to be converted
	 * @param targetType the type of the converted object
	 * @param targetOwner the owner of the converted object
	 * @param <T> the Kernel type of the object to bind
	 * @return an object owned by the target owner, or <code>null</code> if o is <code>null</code> or is a {@link Proxy} that refers to a dead object
	 * @throws IllegalAccessError if the given object cannot be bounded to the given type
	 * @throws IllegalArgumentException if the given type is not a shared interface
	 * @throws IllegalStateException if <code>targetOwner</code> is not in the {@link State#STARTED} state.
	 */
	@Nullable
	public static <T> T bind(@Nullable T o, Class<T> targetType, Feature targetOwner) {
		throw new RuntimeException();
	}

	/**
	 * Tells whether the given class is a shared interface (i.e. an interface owned by a Feature and defined as shared).
	 * @param c the class to test
	 * @return <code>true</code> if the class is a shared interface, <code>false</code> otherwise
	 */
	public static boolean isSharedInterface(Class<?> c){
		throw new RuntimeException();
	}

	/**
	 * Allocates a new {@link Proxy} and sets its reference to the given object.
	 * @param <T> the reference type
	 * @param ref the {@link Proxy} reference
	 * @param owner the owner of the {@link Proxy} instance
	 * @return the new {@link Proxy} instance initialized with the given reference
	 * @throws IllegalStateException if <code>owner</code> is a Feature and not in the {@link State#STARTED} state.
	 */
	public static <T> Proxy<T> newProxy(T ref, Module owner){
		throw new RuntimeException();
	}

	/**
	 * Tells whether the given class is a Kernel API.
	 * @param c the class to test
	 * @return <code>true</code> if the class is a Kernel API, <code>false</code> otherwise
	 */
	public static boolean isAPI(Class<?> c){
		throw new RuntimeException();
	}

	/**
	 * <p>From a shared interface, gets the closest shared interface in the given target Feature.</p>
	 * <p>The closest shared interface is computed by returning the first equivalent shared interface in the target Feature,
	 * starting from the interface <code>si</code> to the interface <code>topInterface</code> (included).</p>
	 * <p>If the owner of the given shared interface is the target, the same shared interface is returned.</p>
	 * @param si a shared interface that extends <code>topInterface</code> interface
	 * @param topInterface a shared interface or an interface owned by the Kernel, which is assignable from <code>si</code>.
	 * @param target the target Feature where to find the closest equivalent shared interface of <code>si</code>
	 * @return the closest shared interface as described, <code>null</code> if not found.
	 * @throws IllegalArgumentException if <code>si</code> is not a shared interface or if <code>topInterface</code> is not an interface or if <code>topInterface</code> is not assignable from <code>fromClass</code>
	 * @see #getEquivalentSharedInterface(Class, Feature)
	 */
	@Nullable
	public static Class<?> getSharedInterface(Class<?> si, Class<?> topInterface, Feature target){
		throw new RuntimeException();
	}

	/**
	 * <p>Gets the equivalent shared interface in the given target Feature.</p>
	 * <p>The equivalent shared interface is the interface owned by the target Feature such as {@link #areEquivalentSharedInterfaces(Class, Class)} is <code>true</code>.</p>
	 * @param si a shared interface
	 * @param target the target Feature where to find the equivalent shared interface of <code>si</code>
	 * @throws IllegalArgumentException if <code>si</code> is not a shared interface
	 * @return the equivalent shared interface, <code>null</code> if not found
	 */
	@Nullable
	public static Class<?> getEquivalentSharedInterface(Class<?> si, Feature target){
		throw new RuntimeException();
	}

	/**
	 * <p>Tells whether the given classes are equivalent shared interfaces.</p>
	 * <p>Two classes are equivalent shared interfaces if they are shared interfaces and have the same fully qualified name.</p>
	 * @param si1 a class to test
	 * @param si2 a class to test
	 * @return <code>true</code> if the given classes are equivalent shared interfaces, <code>false</code> otherwise
	 */
	public static boolean areEquivalentSharedInterfaces(Class<?> si1, Class<?> si2){
		throw new RuntimeException();
	}

	/**
	 * <p>Gets the first shared interface implemented by the given class under the hierarchy of <code>topInterface</code>.
	 * <p>If <code>fromClass</code> is a shared interface it is directly returned.</p>
	 * @param fromClass a class or an interface owned by a {@link Feature} that implements <code>topInterface</code>
	 * @param topInterface an interface implemented by <code>fromClass</code>
	 * @return the shared interface type as described or <code>null</code> if no shared interface found
	 * @throws IllegalArgumentException if the given class is an array or is owned by the Kernel or if <code>topInterface</code> is not an interface or if <code>topInterface</code> is not assignable from <code>fromClass</code>
	 */
	@Nullable
	public static Class<?> getImplementedSharedInterface(Class<?> fromClass, Class<?> topInterface){
		throw new RuntimeException();
	}
}
