package com.wesabe.grendel.openpgp;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;

import com.wesabe.grendel.util.Iterators;

/**
 * A {@link MasterKey} and {@link SubKey} pair.
 * 
 * @author coda
 */
public class KeySet {
	private final MasterKey masterKey;
	private final SubKey subKey;
	
	public static KeySet load(PGPSecretKeyRing keyRing) throws CryptographicException {
		final List<PGPSecretKey> secretKeys = Iterators.toList(keyRing.getSecretKeys());
		final MasterKey masterKey = MasterKey.load(secretKeys.get(0));
		final SubKey subKey = SubKey.load(secretKeys.get(1), masterKey);
		
		return new KeySet(masterKey, subKey);
	}
	
	protected KeySet(MasterKey masterKey, SubKey subKey) {
		this.masterKey = masterKey;
		this.subKey = subKey;
	}
	
	/**
	 * Returns the keyset's {@link MasterKey}.
	 */
	public MasterKey getMasterKey() {
		return masterKey;
	}
	
	/**
	 * Returns the keyset's {@link SubKey}.
	 */
	public SubKey getSubKey() {
		return subKey;
	}
	
	/**
	 * Writes the keyset in encoded form, to {@code output}.
	 * 
	 * @param output an {@link OutputStream}
	 * @throws IOException if there is an error writing to {@code output}
	 */
	public void encode(OutputStream output) throws IOException {
		masterKey.getSecretKey().encode(output);
		subKey.getSecretKey().encode(output);
	}
	
	/**
	 * Returns the keyset in encoded form.
	 * 
	 * @throws IOException if there is an error encoding the keyset
	 */
	public byte[] getEncoded() throws IOException {
		final ByteArrayOutputStream output = new ByteArrayOutputStream();
		encode(output);
		return output.toByteArray();
	}
	
	@Override
	public String toString() {
		return String.format("[%s, %s]", masterKey, subKey);
	}
	
	/**
	 * Given the keyset's passphrase, unlocks the secret keys and returns an
	 * {@link UnlockedKeySet} equivalent of {@code this}.
	 * 
	 * @param passphrase the key's passphrase
	 * @return a {@link UnlockedKeySet} equivalent of {@code this}
	 * @throws CryptographicException if {@code passphrase} is incorrect
	 */
	public UnlockedKeySet unlock(char[] passphrase) throws CryptographicException {
		final UnlockedMasterKey unlockedMasterKey = masterKey.unlock(passphrase);
		final UnlockedSubKey unlockedSubKey = subKey.unlock(passphrase);
		return new UnlockedKeySet(unlockedMasterKey, unlockedSubKey);
	}
}

@@ -149,16 +149,62 @@
 .List;%0A%0A
+import org.bouncycastle.openpgp.PGPException;%0A
 import o
@@ -501,16 +501,292 @@
 bKey;%0A%09%0A
+%09public static KeySet load(byte%5B%5D encoded) throws CryptographicException %7B%0A%09%09try %7B%0A%09%09%09return load(new PGPSecretKeyRing(encoded));%0A%09%09%7D catch (IOException e) %7B%0A%09%09%09throw new CryptographicException(e);%0A%09%09%7D catch (PGPException e) %7B%0A%09%09%09throw new CryptographicException(e);%0A%09%09%7D%0A%09%7D%0A%09%0A
 %09public 
@@ -1841,78 +1841,8 @@
 rm.%0A
-%09 * %0A%09 * @throws IOException if there is an error encoding the keyset%0A
 %09 */
@@ -1869,35 +1869,16 @@
 ncoded()
- throws IOException
  %7B%0A%09%09fin
@@ -1940,16 +1940,25 @@
 ream();%0A
+%09%09try %7B%0A%09
 %09%09encode
@@ -1967,16 +1967,82 @@
 utput);%0A
+%09%09%7D catch (IOException e) %7B%0A%09%09%09throw new RuntimeException(e);%0A%09%09%7D%0A
 %09%09return

Make KeySet.load(byte[]) nicer.