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

package com.google.crypto.tink.keyderivation.internal;

import java.util.Iterator;
import com.google.crypto.tink.Key;
import com.google.crypto.tink.KeysetHandle;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.internal.PrimitiveRegistry;
import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
import java.util.List;
import com.google.crypto.tink.KeyStatus;
import java.util.ArrayList;
import com.google.crypto.tink.internal.MonitoringAnnotations;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.internal.KeysetHandleInterface;
import com.google.crypto.tink.keyderivation.KeysetDeriver;
import com.google.crypto.tink.internal.PrimitiveWrapper;

public final class KeysetDeriverWrapper implements PrimitiveWrapper<KeyDeriver, KeysetDeriver>
{
    private static final KeysetDeriverWrapper WRAPPER;
    
    private static void validate(final KeysetHandleInterface keysetHandle) throws GeneralSecurityException {
        if (keysetHandle.getPrimary() == null) {
            throw new GeneralSecurityException("Primitive set has no primary.");
        }
    }
    
    KeysetDeriverWrapper() {
    }
    
    @Override
    public KeysetDeriver wrap(final KeysetHandleInterface keysetHandle, final MonitoringAnnotations annotations, final PrimitiveFactory<KeyDeriver> factory) throws GeneralSecurityException {
        validate(keysetHandle);
        final List<DeriverWithId> derivers = new ArrayList<DeriverWithId>(keysetHandle.size());
        for (int i = 0; i < keysetHandle.size(); ++i) {
            final KeysetHandleInterface.Entry entry = keysetHandle.getAt(i);
            if (entry.getStatus().equals(KeyStatus.ENABLED)) {
                derivers.add(new DeriverWithId(factory.create(entry), entry.getId(), entry.isPrimary()));
            }
        }
        return new WrappedKeysetDeriver((List)derivers);
    }
    
    @Override
    public Class<KeysetDeriver> getPrimitiveClass() {
        return KeysetDeriver.class;
    }
    
    @Override
    public Class<KeyDeriver> getInputPrimitiveClass() {
        return KeyDeriver.class;
    }
    
    public static void register() throws GeneralSecurityException {
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)KeysetDeriverWrapper.WRAPPER);
    }
    
    public static void registerToInternalPrimitiveRegistry(final PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException {
        primitiveRegistryBuilder.registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)KeysetDeriverWrapper.WRAPPER);
    }
    
    static {
        WRAPPER = new KeysetDeriverWrapper();
    }
    
    private static class DeriverWithId
    {
        final KeyDeriver deriver;
        final int id;
        final boolean isPrimary;
        
        DeriverWithId(final KeyDeriver deriver, final int id, final boolean isPrimary) {
            this.deriver = deriver;
            this.id = id;
            this.isPrimary = isPrimary;
        }
    }
    
    @Immutable
    private static class WrappedKeysetDeriver implements KeysetDeriver
    {
        private final List<DeriverWithId> derivers;
        
        private WrappedKeysetDeriver(final List<DeriverWithId> derivers) {
            this.derivers = derivers;
        }
        
        private static KeysetHandle.Builder.Entry deriveAndGetEntry(final byte[] salt, final DeriverWithId deriverWithId) throws GeneralSecurityException {
            if (deriverWithId.deriver == null) {
                throw new GeneralSecurityException("Primitive set has non-full primitives -- this is probably a bug");
            }
            final Key key = deriverWithId.deriver.deriveKey(salt);
            final KeysetHandle.Builder.Entry result = KeysetHandle.importKey(key);
            result.withFixedId(deriverWithId.id);
            if (deriverWithId.isPrimary) {
                result.makePrimary();
            }
            return result;
        }
        
        @Override
        public KeysetHandle deriveKeyset(final byte[] salt) throws GeneralSecurityException {
            final KeysetHandle.Builder builder = KeysetHandle.newBuilder();
            for (final DeriverWithId deriverWithId : this.derivers) {
                builder.addEntry(deriveAndGetEntry(salt, deriverWithId));
            }
            return builder.build();
        }
    }
}
