package bndtools;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.StringTokenizer;

import org.osgi.service.url.AbstractURLStreamHandlerService;

import aQute.lib.base64.Base64;

/**
 * Basic implementation of IETF RFC 2397, the "data" URL scheme
 * (http://tools.ietf.org/html/rfc2397).
 */
public class DataURLStreamHandler extends AbstractURLStreamHandlerService {

	public final static String PROTOCOL = "data";

	@Override
	public URLConnection openConnection(URL u) throws IOException {
		if (!PROTOCOL.equals(u.getProtocol()))
			throw new MalformedURLException("Unsupported protocol");
		return new DataURLConnection(u);
	}

	static class ParseResult {
		String	mediaType	= "text/plain";
		String	charset		= "US-ASCII";
		byte[]	data;
	}

	static final class DataURLConnection extends URLConnection {

		private ParseResult parsed = null;

		DataURLConnection(URL url) {
			super(url);
		}

		@Override
		public void connect() throws IOException {
			parsed = parse(url.getPath());
		}

		static ParseResult parse(String ssp) throws IOException {
			int commaIndex = ssp.indexOf(',');
			if (commaIndex < 0)
				throw new MalformedURLException("missing comma");

			String paramSegment = ssp.substring(0, commaIndex);
			String dataSegment = ssp.substring(commaIndex + 1);

			String mediaType = null;
			boolean base64 = false;
			String charset = "US-ASCII";

			StringTokenizer tokenizer = new StringTokenizer(paramSegment, ";");
			boolean first = true;
			while (tokenizer.hasMoreTokens()) {
				String token = tokenizer.nextToken();
				if (first)
					mediaType = token;
				else if ("base64".equals(token))
					base64 = true;
				else if (token.startsWith("charset="))
					charset = token.substring("charset=".length());
				first = false;
			}

			byte[] bytes;
			if (base64) {
				bytes = Base64.decodeBase64(dataSegment);
			} else {
				String decoded = URLDecoder.decode(dataSegment, charset);
				bytes = decoded.getBytes("UTF-8");
			}

			ParseResult parsed = new ParseResult();
			parsed.data = bytes;
			if (mediaType != null && !mediaType.isEmpty())
				parsed.mediaType = mediaType;
			if (charset != null && !charset.isEmpty())
				parsed.charset = charset;
			return parsed;
		}

		@Override
		public InputStream getInputStream() throws IOException {
			if (parsed == null)
				connect();

			return new ByteArrayInputStream(parsed.data);
		}

		@Override
		public String getContentType() {
			return parsed != null ? parsed.mediaType : null;
		}

		@Override
		public String getContentEncoding() {
			return parsed != null ? parsed.charset : null;
		}

	}

}
