package freenet.pluginmanager;

import freenet.support.Logger;

/**
 * Methods to handle a specific plugin (= set it up and start it)
 * 
 * @author cyberdo
 */
public class PluginHandler {

	/**
	 * Will get all needed info from the plugin, put it into the Wrapper. Then
	 * the Pluginstarter will be greated, and the plugin fedto it, starting the
	 * plugin.
	 * 
	 * the pluginInfoWrapper will then be returned
	 * 
	 * @param plug
	 */
	public static void startPlugin(PluginManager pm, PluginInfoWrapper pi) {
		final PluginStarter ps = new PluginStarter(pm, pi);

		FredPlugin plug = pi.getPlugin();
		ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
		ClassLoader pluginClassLoader = plug.getClass().getClassLoader();
		Thread.currentThread().setContextClassLoader(pluginClassLoader);
		try {
		// We must start the plugin *after startup has finished*
		Runnable job;
		if(!pi.isThreadlessPlugin()) {
			final Thread t = new Thread(ps);
			t.setDaemon(true);
			pi.setThread(t);
			job = new Runnable() {
				@Override
				public void run() {
					t.start();
				}
			};
			pm.getTicker().queueTimedJob(job, 0);
		} else {
			// Avoid NPEs: let it init, then register it.
			plug.runPlugin(pi.getPluginRespirator());
			pm.register(pi);
		}
		} finally {
			Thread.currentThread().setContextClassLoader(oldClassLoader);
		}
	}
	
	private static class PluginStarter implements Runnable {
		private PluginManager pm = null;
		final PluginInfoWrapper pi;
		
		public PluginStarter(PluginManager pm, PluginInfoWrapper pi) {
			this.pm = pm;
			this.pi = pi;
		}
		
		@Override
		public void run() {
				try {
					pm.register(pi);
					pi.getPlugin().runPlugin(pi.getPluginRespirator());
				} catch (Throwable t) {
					Logger.normal(this, "Caught Throwable while running plugin: "+t, t);
					System.err.println("Caught Throwable while running plugin: "+t);
					t.printStackTrace();
				}
				pi.unregister(pm, false); // If not already unregistered
				pm.removePlugin(pi);
		}
		
	}
}
