package me.footlights.core.crypto;

import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.binary.Hex;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import me.footlights.HasBytes;
import me.footlights.core.Config;
import me.footlights.core.ConfigurationError;


/** A fingerprint for a number of bytes. */
public class Fingerprint
{
	public static class Builder
	{
		public Fingerprint build()
		{
			ByteBuffer hash = ByteBuffer.wrap(algorithm.digest(bytes));
			return new Fingerprint(algorithm, hash);
		}

		public Builder setAlgorithm(String a) throws NoSuchAlgorithmException
		{
			algorithm = MessageDigest.getInstance(a);
			return this;
		}

		public Builder setContent(byte[] b) { bytes = b; return this; }
		public Builder setContent(HasBytes h) { return setContent(h.getBytes()); }
		public Builder setContent(ByteBuffer b)
		{
			if (b.isReadOnly())
			{
				bytes = new byte[b.remaining()];
				b.get(bytes);
			}
			else bytes = b.array();

			return this;
		}
		
		private Builder()
		{
			try
			{
				algorithm = MessageDigest.getInstance(
						Config.getInstance().get("crypto.hash.algorithm"));
			}
			catch (NoSuchAlgorithmException e)
			{
				throw new ConfigurationError("Invalid hash algorithm: " + e);
			}
		}

		private MessageDigest algorithm;
		private byte[] bytes;
	}

	public static Builder newBuilder() { return new Builder(); }

	public MessageDigest getAlgorithm() { return algorithm; }

	public boolean matches(ByteBuffer b) { return (0 == bytes.compareTo(b)); }
	public boolean matches(byte[] b) { return matches(ByteBuffer.wrap(b)); }

	public String hex() { return Hex.encodeHexString(bytes.array()); }
	public String base64ish()
	{
		return Base64.encode(bytes.array()).replaceAll("/", "+");
	}

	public ByteBuffer getBytes() { return bytes.asReadOnlyBuffer(); }

	private Fingerprint(MessageDigest hashAlgorithm, ByteBuffer fingerprintBytes)
	{
		this.algorithm = hashAlgorithm;
		this.bytes = fingerprintBytes;
	}

	private MessageDigest algorithm;
	private ByteBuffer bytes;
}

@@ -433,16 +433,714 @@
 print%0A%7B%0A
+%09public static Builder newBuilder() %7B return new Builder(); %7D%0A%0A%09public String encoded()%0A%09%7B%0A%09%09StringBuffer sb = new StringBuffer();%0A%09%09sb.append(algorithm.getAlgorithm().toLowerCase());%0A%09%09sb.append(%22:%22);%0A%09%09sb.append(base64ish());%0A%0A%09%09return sb.toString();%0A%09%7D%0A%0A%09public String hex() %7B return Hex.encodeHexString(bytes.array()); %7D%0A%09public String base64ish()%0A%09%7B%0A%09%09return Base64.encode(bytes.array()).replaceAll(%22/%22, %22+%22);%0A%09%7D%0A%0A%09public MessageDigest getAlgorithm() %7B return algorithm; %7D%0A%0A%09public boolean matches(ByteBuffer b) %7B return (0 == bytes.compareTo(b)); %7D%0A%09public boolean matches(byte%5B%5D b) %7B return matches(ByteBuffer.wrap(b)); %7D%0A%0A%09public ByteBuffer getBytes() %7B return bytes.asReadOnlyBuffer(); %7D%0A%0A
 %09public 
@@ -2106,511 +2106,8 @@
 %09%7D%0A%0A
-%09public static Builder newBuilder() %7B return new Builder(); %7D%0A%0A%09public MessageDigest getAlgorithm() %7B return algorithm; %7D%0A%0A%09public boolean matches(ByteBuffer b) %7B return (0 == bytes.compareTo(b)); %7D%0A%09public boolean matches(byte%5B%5D b) %7B return matches(ByteBuffer.wrap(b)); %7D%0A%0A%09public String hex() %7B return Hex.encodeHexString(bytes.array()); %7D%0A%09public String base64ish()%0A%09%7B%0A%09%09return Base64.encode(bytes.array()).replaceAll(%22/%22, %22+%22);%0A%09%7D%0A%0A%09public ByteBuffer getBytes() %7B return bytes.asReadOnlyBuffer(); %7D%0A
 %0A%09pr

Rework Fingerprint a little bit