/* This code is part of Freenet. It is distributed under the GNU General
 * Public License, version 2 (or at your option any later version). See
 * http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.fcp;

import java.io.File;
import java.net.MalformedURLException;

import freenet.keys.FreenetURI;
import freenet.node.Node;
import freenet.pluginmanager.PluginInfoWrapper;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;

/**
 * load a plugin
 * 
 */
public class LoadPlugin extends FCPMessage {

	static final String NAME = "LoadPlugin";

	static final String TYPENAME_FILE = "file";
	static final String TYPENAME_FREENET = "freenet";
	static final String TYPENAME_OFFICIAL = "official";
	static final String TYPENAME_URL = "url";

	private final String identifier;
	private final String pluginURL;
	private final String urlType;
	private final boolean store;
	private final boolean force;
	private final boolean forceHTTPS;

	public LoadPlugin(SimpleFieldSet fs) throws MessageInvalidException {
		identifier = fs.get("Identifier");
		if(identifier == null)
			throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Must contain an Identifier field", null, false);
		pluginURL = fs.get("PluginURL");
		if(pluginURL == null)
			throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Must contain a PluginURL field", identifier, false);
		String type = fs.get("URLType");
		if ((type != null) && (type.trim().length() > 0))
			urlType = type.trim();
		else
			urlType = null;
		if (urlType != null) {
			if (!(TYPENAME_FILE.equalsIgnoreCase(urlType) ||
					TYPENAME_FREENET.equalsIgnoreCase(urlType) ||
					TYPENAME_OFFICIAL.equalsIgnoreCase(urlType) ||
					TYPENAME_URL.equalsIgnoreCase(urlType)))
				throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Unknown URL type: '"+urlType+"'", identifier, false);
		}
		String officialSource = fs.get("OfficialSource");
		if(officialSource != null) {
			if(officialSource.equalsIgnoreCase("https")) {
				force = true;
				forceHTTPS = true;
			} else if(officialSource.equalsIgnoreCase("freenet")) {
				force = true;
				forceHTTPS = false;
			} else {
				throw new MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Unknown OfficialSource '"+officialSource+"'", identifier, false);
			}
		} else {
			force = false;
			forceHTTPS = false;
		}
		store = fs.getBoolean("Store", false);
	}

	@Override
	public SimpleFieldSet getFieldSet() {
		return new SimpleFieldSet(true);
	}

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

	@Override
	public void run(final FCPConnectionHandler handler, final Node node) throws MessageInvalidException {
		if(!handler.hasFullAccess()) {
			throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "LoadPlugin requires full access", identifier, false);
		}
		
		if(!node.pluginManager.isEnabled()) {
		    handler.outputHandler.queue(new ProtocolErrorMessage(ProtocolErrorMessage.PLUGINS_DISABLED, false, "Plugins disabled", identifier, false));
		    return;
		}

		node.executor.execute(new Runnable() {
			@Override
			public void run() {
				String type = null;
				if (urlType == null) {
					if (node.pluginManager.isOfficialPlugin(pluginURL) != null) {
						type = TYPENAME_OFFICIAL;
					} else if (new File(pluginURL).exists()) {
						type = TYPENAME_FILE;
					} else {
						try {
							new FreenetURI(pluginURL);
							type = TYPENAME_FREENET;
						} catch (MalformedURLException e) {
							// FIXME currently i have no idea how to auto detect a proper url,
							// especially distinguish it from typos/mistakes. 
							// so it is disabled for now. saces.
//							try {
//								URL url = new URL(pluginURL);
//								url.getProtocol();
//								TODO: sanitize checks for proper protocols
//							} catch (MalformedURLException e1) {
//							}
						}
					}
					if (type == null) {
						handler.outputHandler.queue(new ProtocolErrorMessage(ProtocolErrorMessage.INVALID_FIELD, false, "Was not able to guess the URL type from URL, check the URL or add a 'URLType' field", identifier, false));
						return;
					}
				} else {
					type = urlType.toLowerCase();
				}
				PluginInfoWrapper pi;
				if (TYPENAME_OFFICIAL.equals(type)) {
					pi = node.pluginManager.startPluginOfficial(pluginURL, store, force, forceHTTPS);
				} else if (TYPENAME_FILE.equals(type)) {
					pi = node.pluginManager.startPluginFile(pluginURL, store);
				} else if (TYPENAME_FREENET.equals(type)) {
					pi = node.pluginManager.startPluginFreenet(pluginURL, store);
				} else if (TYPENAME_URL.equals(type)) {
					pi = node.pluginManager.startPluginURL(pluginURL, store);
				} else {
					Logger.error(this, "This should really not happen!", new Exception("FIXME"));
					handler.outputHandler.queue(new ProtocolErrorMessage(ProtocolErrorMessage.INTERNAL_ERROR, false, "This should really not happen! See logs for details.", identifier, false));
					return;
				}
				if (pi == null) {
					handler.outputHandler.queue(new ProtocolErrorMessage(ProtocolErrorMessage.NO_SUCH_PLUGIN, false, "Plugin '"+ pluginURL + "' does not exist or is not a FCP plugin", identifier, false));
				} else {
					handler.outputHandler.queue(new PluginInfoMessage(pi, identifier, true));
				}
			}
		}, "Load Plugin");
	}

}
