package org.bouncycastle.openpgp;

import java.io.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import org.bouncycastle.bcpg.BCPGOutputStream;

/**
 * Often a PGP key ring file is made up of a succession of master/sub-key key rings.
 * If you want to read an entire public key file in one hit this is the class for you.
 */
public class PGPPublicKeyRingCollection 
{
	private HashMap	pubRings = new HashMap();
	private ArrayList	order = new ArrayList();
	
	public PGPPublicKeyRingCollection(
		byte[]	encoding)
		throws IOException, PGPException
	{
		this(new ByteArrayInputStream(encoding));
	}
	
	public PGPPublicKeyRingCollection(
		InputStream	in)
		throws IOException, PGPException
	{
		PGPObjectFactory	pgpFact = new PGPObjectFactory(in);
		PGPPublicKeyRing		pgpPub = null;
		
		while ((pgpPub = (PGPPublicKeyRing)pgpFact.nextObject()) != null)
		{
			Long	key = new Long(pgpPub.getPublicKey().getKeyID());
			
			pubRings.put(key, pgpPub);
			order.add(key);
		}
	}
	
	public PGPPublicKeyRingCollection(
		Collection	collection)
		throws IOException, PGPException
	{
		Iterator					it = collection.iterator();
		
		while (it.hasNext())
		{
			PGPPublicKeyRing	pgpPub = (PGPPublicKeyRing)it.next();
			
			Long	key = new Long(pgpPub.getPublicKey().getKeyID());
			
			pubRings.put(key, pgpPub);
			order.add(key);
		}
	}
	
	/**
	 * return the public key rings making up this collection.
	 */
	public Iterator getKeyRings()
	{
		return pubRings.values().iterator();
	}
	
	/**
	 * Return the PGP public key associated with the given key id.
	 * 
	 * @param keyID
	 * @return the PGP public key
	 * @throws PGPException
	 */
	public PGPPublicKey getPublicKey(
		long		keyID) 
		throws PGPException
	{	
		Iterator	it = this.getKeyRings();
		
		while (it.hasNext())
		{
			PGPPublicKeyRing	pubRing = (PGPPublicKeyRing)it.next();
			PGPPublicKey		pub = pubRing.getPublicKey(keyID);
			
			if (pub != null)
			{
				return pub;
			}
		}
	
		return null;
	}
	
	/**
	 * Return the public key ring which contains the key referred to by keyID.
	 * 
	 * @param keyID
	 * @return the public key ring
	 * @throws PGPException
	 */
	public PGPPublicKeyRing getPublicKeyRing(
		long	keyID) 
		throws PGPException
	{
		Long	id = new Long(keyID);
		
		if (pubRings.containsKey(id))
		{
			return (PGPPublicKeyRing)pubRings.get(id);
		}
		
		Iterator	it = this.getKeyRings();
		
		while (it.hasNext())
		{
			PGPPublicKeyRing	pubRing = (PGPPublicKeyRing)it.next();
			PGPPublicKey		pub = pubRing.getPublicKey(keyID);
			
			if (pub != null)
			{
				return pubRing;
			}
		}
	
		return null;
	}
	
	public byte[] getEncoded() 
		throws IOException
	{
		ByteArrayOutputStream	bOut = new ByteArrayOutputStream();
		
		this.encode(bOut);
		
		return bOut.toByteArray();
	}
	
	public void encode(
		OutputStream	outStream) 
		throws IOException
	{
		BCPGOutputStream	out;
		
		if (outStream instanceof BCPGOutputStream)
		{
			out = (BCPGOutputStream)outStream;
		}
		else
		{
			out = new BCPGOutputStream(outStream);
		}

		Iterator	it = order.iterator();
		while (it.hasNext())
		{
			PGPPublicKeyRing	sr = (PGPPublicKeyRing)pubRings.get(it.next());
			
			sr.encode(out);
		}
	}
}
