package com.technica.pbac.classpath.protocol;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

/**
 * http://stackoverflow.com/questions/861500/url-to-load-resources-from-the-
 * Allow classpath:file.ext so PDP can be fed classpath: URLs that work from
 * servlet and/or junit test cases. 
 */
public class ClasspathURL
{
	private final static Logger log = Logger.getLogger(ClasspathURL.class.getName());

	public static void init()
	{
		log.info("ClasspathURL.init()");
		ClassLoader cl = ClasspathURL.class.getClassLoader();
		init(cl);
	}

	public static void init(ClassLoader cl)
	{
		log.info("ClasspathURL.init:"+cl);
		try
		{
			Handler clh = new Handler(cl);
			HandlerFactory csh = 
				new HandlerFactory("classpath", clh);
			URL.setURLStreamHandlerFactory(csh);
		}
		catch (java.lang.Error e)
		{
			log.info("URL.setURLStreamHandler called more than once. Not a problem; ignoring");
//			e.printStackTrace();
		}
	}
	
	static class Handler 
		extends URLStreamHandler
	{
		private final ClassLoader classLoader;

		public Handler(ClassLoader classLoader)
		{
			this.classLoader = classLoader;
		}

		@Override
		protected URLConnection openConnection(URL u) throws IOException
		{
			log.info("ClassLoaderURLHandler.openConnection:"+u);
			final URL resourceUrl = classLoader.getResource(u.getPath());
			if (resourceUrl == null)
			{
				URL systemUrl = classLoader.getSystemResource(u.getPath());
				if (systemUrl == null)
				{
					throw new IOException("ClasspathURL could not locate: "+u);
				}
				else
				{
					return systemUrl.openConnection();
				}
			}
			return resourceUrl.openConnection();
		}
	}

	static class HandlerFactory 
		implements URLStreamHandlerFactory
	{

		private final Map<String, URLStreamHandler> protocolHandlers;

		public HandlerFactory(String protocol, URLStreamHandler urlHandler)
		{
			protocolHandlers = new HashMap<String, URLStreamHandler>();
			addHandler(protocol, urlHandler);
		}

		public void addHandler(String protocol, URLStreamHandler urlHandler)
		{
			protocolHandlers.put(protocol, urlHandler);
		}

		@Override
		public URLStreamHandler createURLStreamHandler(String protocol)
		{
			return protocolHandlers.get(protocol);
		}
		
		public URLStreamHandler getHandler(String protocol)
		{
			return createURLStreamHandler(protocol);
		}
	}
}
