package freenet.clients.http;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import freenet.client.HighLevelSimpleClient;
import freenet.config.InvalidConfigValueException;
import freenet.config.SubConfig;
import freenet.l10n.NodeL10n;
import freenet.node.Node;
import freenet.support.Logger;
import freenet.support.api.HTTPRequest;
import freenet.support.api.StringArrCallback;

/**
 * Symlinker Toadlet
 * 
 * Provide alias to other toadlet URLs by throwing {@link RedirectException}.
 */
public class SymlinkerToadlet extends Toadlet {	
	private final HashMap<String, String> linkMap = new HashMap<String, String>();
	private final Node node;
	SubConfig tslconfig;
	
	public SymlinkerToadlet(HighLevelSimpleClient client,final Node node) {
		super(client);
		this.node = node;
		tslconfig = node.getConfig().createSubConfig("toadletsymlinker");
		tslconfig.register("symlinks", null, 9, true, false, "SymlinkerToadlet.symlinks", "SymlinkerToadlet.symlinksLong", 
        		new StringArrCallback() {
			@Override
			public String[] get() {
				return getConfigLoadString();
			}
			@Override
			public void set(String[] val) throws InvalidConfigValueException {
				//if(storeDir.equals(new File(val))) return;
				// FIXME
				throw new InvalidConfigValueException("Cannot set the plugins that's loaded.");
			}

			        @Override
					public boolean isReadOnly() {
				        return true;
			        }
		});
		
		String fns[] = tslconfig.getStringArr("symlinks");
		if (fns != null) {
			for (String fn : fns) {
				String tuple[] = fn.split("#");
				if (tuple.length == 2)
					addLink(tuple[0], tuple[1], false);
			}
		}
		
		tslconfig.finishedInitialization();
		
		addLink("/sl/search/", "/plugins/plugins.Librarian/", false);
		addLink("/sl/gallery/", "/plugins/plugins.TestGallery/", false);
	}
	
	public boolean addLink(String alias, String target, boolean store) {
		boolean ret;
		synchronized (linkMap) {
			if (alias.equals(linkMap.put(alias, target))) {
				ret = true;
			} else  {
				ret = false;
			}
			Logger.normal(this, "Adding link: " + alias + " => " + target);
		}
		if(store) node.getClientCore().storeConfig();
		return ret;
	}
	
	public boolean removeLink(String alias, boolean store) {
		boolean ret;
		synchronized (linkMap) {
			Object o;
			if ((o = linkMap.remove(alias))!= null)
				ret = true;
			else 
				ret = false;
			
			Logger.normal(this, "Removing link: " + alias + " => " + o);
		}
		if(store) node.getClientCore().storeConfig();
		return ret;
	}
	
	private String[] getConfigLoadString() {
		String retarr[] = new String[linkMap.size()];
		synchronized (linkMap) {
			int i = 0;
			for (Map.Entry<String,String> entry : linkMap.entrySet()) {
				retarr[i++] = entry.getKey() + '#' + entry.getValue();
			}
		}
		return retarr;
	}

	public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx)
	throws ToadletContextClosedException, IOException, RedirectException {
		String path = uri.getPath();
		String foundkey = null;
		String foundtarget = null;
		synchronized (linkMap) {
			for (Map.Entry<String,String> entry : linkMap.entrySet()) {
				String key = entry.getKey();
				if (path.startsWith(key)) {
					foundkey = key;
					foundtarget = entry.getValue();
				}
			}
		}
		
		// TODO redirect to errorpage
		if ((foundtarget == null) || (foundkey == null)) {
			writeTextReply(ctx, 404, "Not found", 
					NodeL10n.getBase().getString("StaticToadlet.pathNotFound"));
			return;
		}
		
		path = foundtarget + path.substring(foundkey.length());
		URI outuri = null;
		try {
			outuri = new URI(null, null,
			         path, uri.getQuery(), uri.getFragment());
		} catch (URISyntaxException e) {
			// TODO Handle error somehow
			writeHTMLReply(ctx, 200, "OK", e.getMessage());
			return;
		}
		
		uri.getRawQuery();
	    
		throw new RedirectException(outuri);
	}

	@Override
	public String path() {
		return "/sl/";
	}
	
}
