package org.bouncycastle.jce.cert;

import java.io.InputStream;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.cert.CRL;
import java.security.cert.CRLException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * Uses {@link CertUtil CertUtil} to actualiy load the SPI classes.
 *
 * @see CertUtil
 **/
public class CertificateFactory
{
	private CertificateFactorySpi certFacSpi;
	private Provider provider;
	private String type;

    protected CertificateFactory(
		CertificateFactorySpi certFacSpi,
		Provider provider,
		String type)
	{
		this.certFacSpi = certFacSpi;
		this.provider = provider;
		this.type = type;
	}

    public final CRL generateCRL(InputStream inStream)
	throws CRLException
	{
		return certFacSpi.engineGenerateCRL(inStream);
	}

    public final Collection generateCRLs(InputStream inStream)
	throws CRLException
	{
		return certFacSpi.engineGenerateCRLs(inStream);
	}

    public final Certificate generateCertificate(InputStream inStream)
	throws CertificateException
	{
		return certFacSpi.engineGenerateCertificate(inStream);
	}

    public final /*Sk13 Vector*/ Collection generateCertificates(InputStream inStream)
	throws CertificateException
	{
		return certFacSpi.engineGenerateCertificates(inStream);
	}

	/**
	 * Returns an iteration of the <code>CertPath</code> encodings supported 
	 * by this certificate factory, with the default encoding first. See 
	 * Appendix A in the 
	 * Java Certification Path API Programmer's Guide for information about 
	 * standard encoding names and their formats.<br />
	 * <br />
	 * Attempts to modify the returned <code>Iterator</code> via its 
	 * <code>remove</code> method result in an 
	 * <code>UnsupportedOperationException</code>.
	 *
	 * @return an <code>Iterator</code> over the names of the supported
	 *         <code>CertPath</code> encodings (as <code>String</code>s)
	 */
    public final Iterator getCertPathEncodings()
	{
		return certFacSpi.engineGetCertPathEncodings();
	}

	/**
	 * Generates a <code>CertPath</code> object and initializes it with
	 * the data read from the <code>InputStream</code> inStream. The data
	 * is assumed to be in the default encoding. The name of the default
	 * encoding is the first element of the <code>Iterator</code> returned by
	 * the {@link #getCertPathEncodings getCertPathEncodings} method.
	 *
	 * @param inStream an <code>InputStream</code> containing the data
	 *
	 * @return a <code>CertPath</code> initialized with the data from the
	 *   <code>InputStream</code>
	 *
	 * @exception CertificateException if an exception occurs while decoding
	 */
    public final CertPath generateCertPath(InputStream inStream)
	throws CertificateException
	{
		return certFacSpi.engineGenerateCertPath(inStream);
	}

	/**
	 * Generates a <code>CertPath</code> object and initializes it with
	 * the data read from the <code>InputStream</code> inStream. The data
	 * is assumed to be in the specified encoding. See Appendix A in the 
	 * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA">
	 * Java Certification Path API Programmer's Guide</a>
	 * for information about standard encoding names and their formats.
	 *
	 * @param inStream an <code>InputStream</code> containing the data
	 * @param encoding the encoding used for the data
	 *
	 * @return a <code>CertPath</code> initialized with the data from the
	 *   <code>InputStream</code>
	 *
	 * @exception CertificateException if an exception occurs while decoding or
	 *   the encoding requested is not supported
	 */
    public final CertPath generateCertPath(InputStream inStream, String encoding)
	throws CertificateException
	{
		return certFacSpi.engineGenerateCertPath(inStream, encoding);
	}

	/**
	 * Generates a <code>CertPath</code> object and initializes it with
	 * a <code>List</code> of <code>Certificate</code>s.<br />
	 * <br />
	 * The certificates supplied must be of a type supported by the
	 * <code>CertificateFactory</code>. They will be copied out of the supplied
	 * <code>List</code> object.
	 *
	 * @param certificates a <code>List</code> of <code>Certificate</code>s
	 *
	 * @return a <code>CertPath</code> initialized with the supplied list of
	 *   certificates
	 *
	 * @exception CertificateException if an exception occurs
	 */
    public final CertPath generateCertPath(List certificates)
	throws CertificateException
	{
		return certFacSpi.engineGenerateCertPath( certificates );
	}

    public static final CertificateFactory getInstance(String type)
	throws CertificateException
	{
        try
        {
            CertUtil.Implementation  imp = CertUtil.getImplementation("CertificateFactory", type, (String)null);

            if (imp != null)
            {
                return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type);
            }

            throw new CertificateException("can't find type " + type);
        }
        catch (NoSuchProviderException e)
        {
            throw new CertificateException(type + " not found");
        }
	}

    public static final CertificateFactory getInstance(
		String type,
		String provider)
	throws CertificateException, NoSuchProviderException
	{
        CertUtil.Implementation  imp = CertUtil.getImplementation("CertificateFactory", type, provider);

        if (imp != null)
        {
            return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type);
        }

        throw new CertificateException("can't find type " + type);
	}

    public final Provider getProvider()
	{
		return provider;
	}

    public final String getType()
	{
		return type;
	}
}
