/*
 ************************************************************************
 *
 * Copyright (c) 2003-2004, C&C Research Laboratories, NEC Europe Ltd.
 *
 * Copyright in this software belongs to C&C Research Laboratories,
 * Rathausallee 10, 53757 Sankt Augustin, Germany.
 *
 * This software may not be used, sold, licensed, transferred, copied
 * or reproduced in whole or in part in any manner or form or in or
 * on any media by any person other than in accordance with the terms
 * of the Licence Agreement supplied with the software, or otherwise
 * without the prior written consent of the copyright owners.
 *
 * This software is distributed WITHOUT ANY WARRANTY, without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE, except where stated in the Licence Agreement supplied with
 * the software.
 *
 *  Created By :           G.A. Kohring
 *  Created for Project :  GEMSS (IST-2001-37153)
 *
 ************************************************************************
 */

package de.nece.ccrle.sandbox;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CRL;
import java.security.cert.CRLException;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

/**
 * A class for retrieving Certificates and CRLs from a repository
 * organized as a directory with flat files containing certificates and
 * crls.
 *
 * @author Greg Kohring
 */
public class CertStoreLDR {

    private File certDir;

    private static Logger logger =
                       Logger.getLogger( CertStoreLDR.class.getName() );
                                                                                


    /**
     * Create a new repository from the specified directory containing the
     * specified certificate types.
     * 
     * @param certDir the <code>File</code> object containing the directory
     *      from which to retrieve certicates.
     * @param type a <code>String</code> containing the name of certificate 
     *      type contained within this repository. Currently only the
     *      "X.509" type is supported.
     * @throws CertificateException if the specified type is not supported.
     */
    public CertStoreLDR( File certDir, String type )
                                    throws CertificateException{
        this.certDir = certDir;
        if ( !type.equals( "X.509" ) ){
            throw new CertificateException( 
                    "Unsupported certifcate type: " + type );
        }
    }

    /**
     * Retrieves all the CRLs in this repository.
     *
     * @return a <code>Collection</code> containing <code>X509CRL</code> 
     *      objects.
     * @throws CertStoreException if an exception occurs
     */
    public Collection getCRLs() throws CertStoreException {
        try {
            return getType( CRL.class );
        } catch ( CertificateException  ce ){
            throw new CertStoreException( ce.getMessage() );
        }
    }

    /**
     * Treats all Certificates in the repository as trusted and returns
     * them as <code>TrustAnchor</code>s.
     *
     * @return a <code>Collection</code> containing <code>TrustAnchor</code> 
     *      objects.
     * @throws CertStoreException if an exception occurs
     */
    public Collection getTrustAnchors() throws CertStoreException {
        try {
            return getType( TrustAnchor.class );
        } catch ( CertificateException  ce ){
            throw new CertStoreException( ce.getMessage() );
        }
    }

    /**
     * Retrieves all the Certificates in this repository.
     *
     * @return a <code>Collection</code> containing <code>Certificates</code> 
     *      of the type appropriate to this repository.
     * @throws CertStoreException if an exception occurs
     */
    public Collection getCertificates() throws CertificateException {
        try {
            return getType( X509Certificate.class );
        } catch ( CertificateException  ce ){
            throw new CertificateException( ce.getMessage() );
        }
    }


    private X509Certificate getNextX509Certificate( InputStream is, 
                                                    CertificateFactory cf )
                 throws CertificateException {

        return (X509Certificate) cf.generateCertificate( is );
    }

    private TrustAnchor getNextTrustAnchor( InputStream is, 
                                                    CertificateFactory cf )
                 throws CertificateException {

        X509Certificate x509Cert = 
                    (X509Certificate) cf.generateCertificate( is ); 

        return ( new TrustAnchor( x509Cert, null ) );
    }

    private CRL getNextCRL( InputStream is, CertificateFactory cf )
                throws CRLException {
        return cf.generateCRL( is ); 
    }

    private Set getType( Class type) throws CertificateException {

        Set certs = new HashSet();

        File certFiles[] = certDir.listFiles();

        BufferedInputStream bis = null;
        CertificateFactory cf = CertificateFactory.getInstance( "X.509" );

        for ( int file = 0; file < certFiles.length; file++ ){
            bis = null;
            try {
                bis = new BufferedInputStream(
                                    new FileInputStream( certFiles[file] ) );

                while ( bis.available() > 0 ) {

                    if ( type.equals( TrustAnchor.class) ) {
                        certs.add( getNextTrustAnchor( bis, cf ) );
                    } else if ( type.equals( CRL.class) ) {
                        certs.add( getNextCRL( bis, cf ) );
                    } else if ( type.equals( X509Certificate.class) ) {
                        certs.add( getNextX509Certificate( bis, cf ) );
                    }
                }

            } catch ( Exception e ){
                    // Skip this file, but log the message
                    logger.info( e.getMessage() );
            } finally {
                try {
                    if ( bis != null ) bis.close();
                } catch ( IOException ioe ){
                    // ignore, we got what we needed.
                    logger.info( ioe.getMessage() );
                }
            }

        }

        return certs;

    }


}
