// 
// Decompiled by Procyon v0.6.0
// 

package com.google.crypto.tink.subtle;

import java.util.Iterator;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import java.security.Security;
import java.util.ArrayList;
import java.security.Provider;
import java.util.List;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import javax.crypto.KeyAgreement;
import java.security.MessageDigest;
import java.security.Signature;
import javax.crypto.Mac;
import javax.crypto.Cipher;

public final class EngineFactory<T_WRAPPER extends EngineWrapper<JcePrimitiveT>, JcePrimitiveT>
{
    private final Policy<JcePrimitiveT> policy;
    public static final EngineFactory<EngineWrapper.TCipher, Cipher> CIPHER;
    public static final EngineFactory<EngineWrapper.TMac, Mac> MAC;
    public static final EngineFactory<EngineWrapper.TSignature, Signature> SIGNATURE;
    public static final EngineFactory<EngineWrapper.TMessageDigest, MessageDigest> MESSAGE_DIGEST;
    public static final EngineFactory<EngineWrapper.TKeyAgreement, KeyAgreement> KEY_AGREEMENT;
    public static final EngineFactory<EngineWrapper.TKeyPairGenerator, KeyPairGenerator> KEY_PAIR_GENERATOR;
    public static final EngineFactory<EngineWrapper.TKeyFactory, KeyFactory> KEY_FACTORY;
    
    public static List<Provider> toProviderList(final String... providerNames) {
        final List<Provider> providers = new ArrayList<Provider>();
        for (final String s : providerNames) {
            final Provider p = Security.getProvider(s);
            if (p != null) {
                providers.add(p);
            }
        }
        return providers;
    }
    
    public EngineFactory(final T_WRAPPER instanceBuilder) {
        if (TinkFipsUtil.useOnlyFips()) {
            this.policy = new FipsPolicy<JcePrimitiveT>((EngineWrapper)instanceBuilder);
        }
        else if (SubtleUtil.isAndroid()) {
            this.policy = new AndroidPolicy<JcePrimitiveT>((EngineWrapper)instanceBuilder);
        }
        else {
            this.policy = new DefaultPolicy<JcePrimitiveT>((EngineWrapper)instanceBuilder);
        }
    }
    
    public JcePrimitiveT getInstance(final String algorithm) throws GeneralSecurityException {
        return this.policy.getInstance(algorithm);
    }
    
    JcePrimitiveT getInstance(final String algorithm, final List<Provider> preferredProviders) throws GeneralSecurityException {
        return this.policy.getInstance(algorithm, preferredProviders);
    }
    
    static {
        CIPHER = new EngineFactory<EngineWrapper.TCipher, Cipher>(new EngineWrapper.TCipher());
        MAC = new EngineFactory<EngineWrapper.TMac, Mac>(new EngineWrapper.TMac());
        SIGNATURE = new EngineFactory<EngineWrapper.TSignature, Signature>(new EngineWrapper.TSignature());
        MESSAGE_DIGEST = new EngineFactory<EngineWrapper.TMessageDigest, MessageDigest>(new EngineWrapper.TMessageDigest());
        KEY_AGREEMENT = new EngineFactory<EngineWrapper.TKeyAgreement, KeyAgreement>(new EngineWrapper.TKeyAgreement());
        KEY_PAIR_GENERATOR = new EngineFactory<EngineWrapper.TKeyPairGenerator, KeyPairGenerator>(new EngineWrapper.TKeyPairGenerator());
        KEY_FACTORY = new EngineFactory<EngineWrapper.TKeyFactory, KeyFactory>(new EngineWrapper.TKeyFactory());
    }
    
    private static class DefaultPolicy<JcePrimitiveT> implements Policy<JcePrimitiveT>
    {
        private final EngineWrapper<JcePrimitiveT> jceFactory;
        
        private DefaultPolicy(final EngineWrapper<JcePrimitiveT> jceFactory) {
            this.jceFactory = jceFactory;
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm) throws GeneralSecurityException {
            return this.jceFactory.getInstance(algorithm, null);
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm, final List<Provider> preferredProviders) throws GeneralSecurityException {
            for (final Provider provider : preferredProviders) {
                try {
                    return this.jceFactory.getInstance(algorithm, provider);
                }
                catch (final Exception ex) {
                    continue;
                }
                break;
            }
            return this.getInstance(algorithm);
        }
    }
    
    private static class FipsPolicy<JcePrimitiveT> implements Policy<JcePrimitiveT>
    {
        private final EngineWrapper<JcePrimitiveT> jceFactory;
        
        private FipsPolicy(final EngineWrapper<JcePrimitiveT> jceFactory) {
            this.jceFactory = jceFactory;
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm) throws GeneralSecurityException {
            final List<Provider> conscryptProviders = EngineFactory.toProviderList("GmsCore_OpenSSL", "AndroidOpenSSL", "Conscrypt");
            Exception cause = null;
            for (final Provider provider : conscryptProviders) {
                try {
                    return this.jceFactory.getInstance(algorithm, provider);
                }
                catch (final Exception e) {
                    if (cause != null) {
                        continue;
                    }
                    cause = e;
                    continue;
                }
                break;
            }
            throw new GeneralSecurityException("No good Provider found.", cause);
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm, final List<Provider> preferredProviders) throws GeneralSecurityException {
            return this.getInstance(algorithm);
        }
    }
    
    private static class AndroidPolicy<JcePrimitiveT> implements Policy<JcePrimitiveT>
    {
        private final EngineWrapper<JcePrimitiveT> jceFactory;
        
        private AndroidPolicy(final EngineWrapper<JcePrimitiveT> jceFactory) {
            this.jceFactory = jceFactory;
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm) throws GeneralSecurityException {
            final List<Provider> conscryptProviders = EngineFactory.toProviderList("GmsCore_OpenSSL", "AndroidOpenSSL");
            Exception cause = null;
            for (final Provider provider : conscryptProviders) {
                try {
                    return this.jceFactory.getInstance(algorithm, provider);
                }
                catch (final Exception e) {
                    if (cause != null) {
                        continue;
                    }
                    cause = e;
                    continue;
                }
                break;
            }
            return this.jceFactory.getInstance(algorithm, null);
        }
        
        @Override
        public JcePrimitiveT getInstance(final String algorithm, final List<Provider> preferredProviders) throws GeneralSecurityException {
            return this.getInstance(algorithm);
        }
    }
    
    private interface Policy<JcePrimitiveT>
    {
        JcePrimitiveT getInstance(final String algorithm) throws GeneralSecurityException;
        
        JcePrimitiveT getInstance(final String algorithm, final List<Provider> preferredProviders) throws GeneralSecurityException;
    }
}
