package org.bouncycastle.openpgp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Iterator;

import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.PacketTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SignaturePacket;
import org.bouncycastle.bcpg.UserIDPacket;

/**
 * general class to hold a collection of PGP Public Keys.
 */
public class PGPPublicKeyRing
{
	ArrayList			keys = new ArrayList();
	
	public PGPPublicKeyRing(
		byte[]	encoding)
		throws IOException
	{
		this(new ByteArrayInputStream(encoding));
	}
	
	public PGPPublicKeyRing(
		InputStream	in)
		throws IOException
	{	
		BCPGInputStream	pIn;
		
		if (in instanceof BCPGInputStream)
		{
			pIn = (BCPGInputStream)in;
		}
		else
		{
			pIn = new BCPGInputStream(in);
		}
		
		PublicKeyPacket	pubPk;
		ArrayList			ids = new ArrayList();
		ArrayList			idSigs = new ArrayList();
		MessageDigest 	sha;
		
        try
        {
            sha = MessageDigest.getInstance("SHA1");
        }
        catch (NoSuchAlgorithmException e)
        {
 			throw new IOException("can't find SHA1 digest");
        }
		
		pubPk = (PublicKeyPacket)pIn.readPacket();
		
		while (pIn.nextPacketTag() == PacketTags.USER_ID)
		{
			UserIDPacket	id = (UserIDPacket)pIn.readPacket();
			ArrayList		sigList = new ArrayList();
			
			ids.add(id.getID());
			idSigs.add(sigList);

			while (pIn.nextPacketTag() == PacketTags.SIGNATURE)
			{
				try
                {
                    sigList.add(new PGPSignature(pIn));
                }
                catch (PGPException e)
                {
                    throw new IOException("can't create signature object: " + e);
                }
			}
		}
		
		keys.add(new PGPPublicKey(pubPk, sha, ids, idSigs));
		
		while (pIn.nextPacketTag() == PacketTags.PUBLIC_SUBKEY)
		{
			pIn.readPacket();
			SignaturePacket	sig = (SignaturePacket)pIn.readPacket();
		}
	}

	/**
	 * Return the first public key in the ring.
	 * 
	 * @return PGPPublicKey
	 */
	public PGPPublicKey getPublicKey()
	{
		return (PGPPublicKey)keys.get(0);
	}
	
	/**
	 * Return the public key refered to by the passed in keyID if it
	 * is present.
	 * 
	 * @param keyID
	 * @return PGPPublicKey
	 * @throws PGPException
	 * @throws NoSuchProviderException
	 */
	public PGPPublicKey getPublicKey(
		long		keyID)
		throws PGPException, NoSuchProviderException
	{	
		for (int i = 0; i != keys.size(); i++)
		{
			PGPPublicKey	k = (PGPPublicKey)keys.get(i);
			
			if (keyID == k.getKeyID())
			{
				return k;
			}
		}
	
		return null;
	}
	
	/**
	 * Return an iterator containing all the public keys.
	 * 
	 * @return Iterator
	 */
	public Iterator getPublicKeys()
	{
		return keys.iterator();
	}
	
	public byte[] getEncoded() 
		throws IOException
	{
		ByteArrayOutputStream	bOut = new ByteArrayOutputStream();
		
		this.encode(bOut);
		
		return bOut.toByteArray();
	}
	
	public void encode(
		OutputStream	outStream) 
		throws IOException
	{
		for (int i = 0; i != keys.size(); i++)
		{
			PGPPublicKey	k = (PGPPublicKey)keys.get(i);
			
			k.encode(outStream);
		}
	}
}
