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

package com.google.crypto.tink.internal;

import com.google.crypto.tink.Key;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.KeyManager;
import com.google.crypto.tink.proto.KeyTemplate;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import java.security.GeneralSecurityException;
import javax.annotation.Nullable;
import java.util.HashMap;
import com.google.crypto.tink.Parameters;
import java.util.Map;

public final class MutableKeyCreationRegistry
{
    private final Map<Class<? extends Parameters>, KeyCreator<? extends Parameters>> creators;
    private static final KeyCreator<LegacyProtoParameters> LEGACY_PROTO_KEY_CREATOR;
    private static final MutableKeyCreationRegistry globalInstance;
    
    public MutableKeyCreationRegistry() {
        this.creators = new HashMap<Class<? extends Parameters>, KeyCreator<? extends Parameters>>();
    }
    
    private static LegacyProtoKey createProtoKeyFromProtoParameters(final LegacyProtoParameters parameters, @Nullable final Integer idRequirement) throws GeneralSecurityException {
        final KeyTemplate keyTemplate = parameters.getSerialization().getKeyTemplate();
        final KeyManager<?> manager = KeyManagerRegistry.globalInstance().getUntypedKeyManager(keyTemplate.getTypeUrl());
        if (!KeyManagerRegistry.globalInstance().isNewKeyAllowed(keyTemplate.getTypeUrl())) {
            throw new GeneralSecurityException("Creating new keys is not allowed.");
        }
        final KeyData keyData = manager.newKeyData(keyTemplate.getValue());
        final ProtoKeySerialization protoSerialization = ProtoKeySerialization.create(keyData.getTypeUrl(), keyData.getValue(), keyData.getKeyMaterialType(), keyTemplate.getOutputPrefixType(), idRequirement);
        return new LegacyProtoKey(protoSerialization, InsecureSecretKeyAccess.get());
    }
    
    private static MutableKeyCreationRegistry newRegistryWithLegacyFallback() {
        final MutableKeyCreationRegistry registry = new MutableKeyCreationRegistry();
        try {
            registry.add(MutableKeyCreationRegistry.LEGACY_PROTO_KEY_CREATOR, LegacyProtoParameters.class);
        }
        catch (final GeneralSecurityException e) {
            throw new IllegalStateException("unexpected error.", e);
        }
        return registry;
    }
    
    public static MutableKeyCreationRegistry globalInstance() {
        return MutableKeyCreationRegistry.globalInstance;
    }
    
    public synchronized <ParametersT extends Parameters> void add(final KeyCreator<ParametersT> creator, final Class<ParametersT> parametersClass) throws GeneralSecurityException {
        final KeyCreator<?> existingCreator = this.creators.get(parametersClass);
        if (existingCreator != null && !existingCreator.equals(creator)) {
            throw new GeneralSecurityException("Different key creator for parameters class " + parametersClass + " already inserted");
        }
        this.creators.put(parametersClass, creator);
    }
    
    public Key createKey(final Parameters parameters, @Nullable final Integer idRequirement) throws GeneralSecurityException {
        return this.createKeyTyped(parameters, idRequirement);
    }
    
    private synchronized <ParametersT extends Parameters> Key createKeyTyped(final ParametersT parameters, @Nullable final Integer idRequirement) throws GeneralSecurityException {
        final Class<?> parametersClass = parameters.getClass();
        final KeyCreator<?> creator = this.creators.get(parametersClass);
        if (creator == null) {
            throw new GeneralSecurityException("Cannot create a new key for parameters " + parameters + ": no key creator for this class was registered.");
        }
        final KeyCreator<ParametersT> castCreator = (KeyCreator<ParametersT>)creator;
        return castCreator.createKey(parameters, idRequirement);
    }
    
    static {
        LEGACY_PROTO_KEY_CREATOR = MutableKeyCreationRegistry::createProtoKeyFromProtoParameters;
        globalInstance = newRegistryWithLegacyFallback();
    }
}
