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

package com.google.crypto.tink.hybrid;

import java.util.Iterator;
import com.google.crypto.tink.hybrid.internal.LegacyFullHybridDecrypt;
import com.google.crypto.tink.internal.PrimitiveRegistry;
import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
import com.google.crypto.tink.internal.MonitoringClient;
import com.google.crypto.tink.internal.MonitoringUtil;
import com.google.crypto.tink.internal.MutableMonitoringRegistry;
import com.google.crypto.tink.KeyStatus;
import com.google.crypto.tink.internal.PrefixMap;
import com.google.crypto.tink.internal.MonitoringAnnotations;
import com.google.crypto.tink.internal.KeysetHandleInterface;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.util.Bytes;
import com.google.crypto.tink.Key;
import com.google.crypto.tink.internal.LegacyProtoKey;
import com.google.crypto.tink.internal.PrimitiveConstructor;
import com.google.crypto.tink.HybridDecrypt;
import com.google.crypto.tink.internal.PrimitiveWrapper;

public class HybridDecryptWrapper implements PrimitiveWrapper<HybridDecrypt, HybridDecrypt>
{
    private static final HybridDecryptWrapper WRAPPER;
    private static final PrimitiveConstructor<LegacyProtoKey, HybridDecrypt> LEGACY_PRIMITIVE_CONSTRUCTOR;
    
    private static Bytes getOutputPrefix(final Key key) throws GeneralSecurityException {
        if (key instanceof HybridPrivateKey) {
            return ((HybridPrivateKey)key).getOutputPrefix();
        }
        if (key instanceof LegacyProtoKey) {
            return ((LegacyProtoKey)key).getOutputPrefix();
        }
        throw new GeneralSecurityException("Cannot get output prefix for key of class " + key.getClass().getName() + " with parameters " + key.getParameters());
    }
    
    HybridDecryptWrapper() {
    }
    
    @Override
    public HybridDecrypt wrap(final KeysetHandleInterface keysetHandle, final MonitoringAnnotations annotations, final PrimitiveFactory<HybridDecrypt> factory) throws GeneralSecurityException {
        final PrefixMap.Builder<HybridDecryptWithId> builder = new PrefixMap.Builder<HybridDecryptWithId>();
        for (int i = 0; i < keysetHandle.size(); ++i) {
            final KeysetHandleInterface.Entry entry = keysetHandle.getAt(i);
            if (entry.getStatus().equals(KeyStatus.ENABLED)) {
                final HybridDecrypt hybridDecrypt = factory.create(entry);
                builder.put(getOutputPrefix(entry.getKey()), new HybridDecryptWithId(hybridDecrypt, entry.getId()));
            }
        }
        MonitoringClient.Logger decLogger;
        if (!annotations.isEmpty()) {
            final MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient();
            decLogger = client.createLogger(keysetHandle, annotations, "hybrid_decrypt", "decrypt");
        }
        else {
            decLogger = MonitoringUtil.DO_NOTHING_LOGGER;
        }
        return new WrappedHybridDecrypt(builder.build(), decLogger);
    }
    
    @Override
    public Class<HybridDecrypt> getPrimitiveClass() {
        return HybridDecrypt.class;
    }
    
    @Override
    public Class<HybridDecrypt> getInputPrimitiveClass() {
        return HybridDecrypt.class;
    }
    
    public static void register() throws GeneralSecurityException {
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)HybridDecryptWrapper.WRAPPER);
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveConstructor(HybridDecryptWrapper.LEGACY_PRIMITIVE_CONSTRUCTOR);
    }
    
    public static void registerToInternalPrimitiveRegistry(final PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException {
        primitiveRegistryBuilder.registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)HybridDecryptWrapper.WRAPPER);
    }
    
    static {
        WRAPPER = new HybridDecryptWrapper();
        LEGACY_PRIMITIVE_CONSTRUCTOR = PrimitiveConstructor.create(LegacyFullHybridDecrypt::create, LegacyProtoKey.class, HybridDecrypt.class);
    }
    
    private static class HybridDecryptWithId
    {
        public final HybridDecrypt hybridDecrypt;
        public final int id;
        
        public HybridDecryptWithId(final HybridDecrypt hybridDecrypt, final int id) {
            this.hybridDecrypt = hybridDecrypt;
            this.id = id;
        }
    }
    
    private static class WrappedHybridDecrypt implements HybridDecrypt
    {
        private final PrefixMap<HybridDecryptWithId> allHybridDecrypts;
        private final MonitoringClient.Logger decLogger;
        
        public WrappedHybridDecrypt(final PrefixMap<HybridDecryptWithId> allHybridDecrypts, final MonitoringClient.Logger decLogger) {
            this.allHybridDecrypts = allHybridDecrypts;
            this.decLogger = decLogger;
        }
        
        @Override
        public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException {
            for (final HybridDecryptWithId hybridDecryptWithId : this.allHybridDecrypts.getAllWithMatchingPrefix(ciphertext)) {
                try {
                    final byte[] result = hybridDecryptWithId.hybridDecrypt.decrypt(ciphertext, contextInfo);
                    this.decLogger.log(hybridDecryptWithId.id, ciphertext.length);
                    return result;
                }
                catch (final GeneralSecurityException ex) {
                    continue;
                }
                break;
            }
            this.decLogger.logFailure();
            throw new GeneralSecurityException("decryption failed");
        }
    }
}
