/FileExtraction/Java_unseen/Wind-Development_WindSpigot/WindSpigot-API/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java
package org.bukkit.plugin.java;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.bukkit.plugin.InvalidPluginException;
import org.bukkit.plugin.PluginDescriptionFile;

/**
 * A ClassLoader for plugins, to allow shared classes across multiple plugins
 */
public final class PluginClassLoader extends URLClassLoader { // Spigot
	public JavaPlugin getPlugin() {
		return plugin;
	} // Spigot

	private final JavaPluginLoader loader;
	private final Map<String, Class<?>> classes = new java.util.concurrent.ConcurrentHashMap<>(); // Spigot
	private final PluginDescriptionFile description;
	private final File dataFolder;
	private final File file;
	final JavaPlugin plugin;
	private JavaPlugin pluginInit;
	private IllegalStateException pluginState;

	// Spigot Start
	static {
		try {
			java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
			if (method != null) {
				boolean oldAccessible = method.isAccessible();
				method.setAccessible(true);
				method.invoke(null);
				method.setAccessible(oldAccessible);
				org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.INFO,
						"Set PluginClassLoader as parallel capable");
			}
		} catch (NoSuchMethodException ex) {
			// Ignore
		} catch (Exception ex) {
			org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING,
					"Error setting PluginClassLoader as parallel capable", ex);
		}
	}
	// Spigot End

	PluginClassLoader(final JavaPluginLoader loader, final ClassLoader parent, final PluginDescriptionFile description,
			final File dataFolder, final File file) throws InvalidPluginException, MalformedURLException {
		super(new URL[] { file.toURI().toURL() }, parent);
		Validate.notNull(loader, "Loader cannot be null");

		this.loader = loader;
		this.description = description;
		this.dataFolder = dataFolder;
		this.file = file;

		try {
			Class<?> jarClass;
			try {
				jarClass = Class.forName(description.getMain(), true, this);
			} catch (ClassNotFoundException ex) {
				throw new InvalidPluginException("Cannot find main class `" + description.getMain() + "'", ex);
			}

			Class<? extends JavaPlugin> pluginClass;
			try {
				pluginClass = jarClass.asSubclass(JavaPlugin.class);
			} catch (ClassCastException ex) {
				throw new InvalidPluginException(
						"main class `" + description.getMain() + "' does not extend JavaPlugin", ex);
			}

			plugin = pluginClass.getDeclaredConstructor().newInstance();
		} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
			throw new InvalidPluginException("No public constructor", ex);
		} catch (InstantiationException ex) {
			throw new InvalidPluginException("Abnormal plugin type", ex);
		}
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		return findClass(name, true);
	}

	Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException {
		if (name.startsWith("org.bukkit.") || name.startsWith("net.minecraft.")) {
			throw new ClassNotFoundException(name);
		}
		Class<?> result = classes.get(name);

		if (result == null) {
			if (checkGlobal) {
				result = loader.getClassByName(name);
			}

			if (result == null) {
				result = super.findClass(name);

				if (result != null) {
					loader.setClass(name, result);
				}
			}

			classes.put(name, result);
		}

		return result;
	}

	Set<String> getClasses() {
		return classes.keySet();
	}

	synchronized void initialize(JavaPlugin javaPlugin) {
		Validate.notNull(javaPlugin, "Initializing plugin cannot be null");
		Validate.isTrue(javaPlugin.getClass().getClassLoader() == this,
				"Cannot initialize plugin outside of this class loader");
		if (this.plugin != null || this.pluginInit != null) {
			throw new IllegalArgumentException("Plugin already initialized!", pluginState);
		}

		pluginState = new IllegalStateException("Initial initialization");
		this.pluginInit = javaPlugin;

		javaPlugin.init(loader, loader.server, description, dataFolder, file, this);
	}
}
