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

package com.google.crypto.tink.internal;

import com.google.crypto.tink.util.Bytes;
import java.util.Objects;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.crypto.tink.Parameters;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.Key;
import javax.annotation.Nullable;
import com.google.crypto.tink.SecretKeyAccess;
import java.util.HashMap;
import java.util.Map;

public final class SerializationRegistry
{
    private final Map<SerializerIndex, KeySerializer<?, ?>> keySerializerMap;
    private final Map<ParserIndex, KeyParser<?>> keyParserMap;
    private final Map<SerializerIndex, ParametersSerializer<?, ?>> parametersSerializerMap;
    private final Map<ParserIndex, ParametersParser<?>> parametersParserMap;
    
    private SerializationRegistry(final Builder builder) {
        this.keySerializerMap = new HashMap<SerializerIndex, KeySerializer<?, ?>>(builder.keySerializerMap);
        this.keyParserMap = new HashMap<ParserIndex, KeyParser<?>>(builder.keyParserMap);
        this.parametersSerializerMap = new HashMap<SerializerIndex, ParametersSerializer<?, ?>>(builder.parametersSerializerMap);
        this.parametersParserMap = new HashMap<ParserIndex, ParametersParser<?>>(builder.parametersParserMap);
    }
    
    public <SerializationT extends Serialization> boolean hasParserForKey(final SerializationT serializedKey) {
        final ParserIndex index = new ParserIndex((Class)serializedKey.getClass(), serializedKey.getObjectIdentifier());
        return this.keyParserMap.containsKey(index);
    }
    
    public <SerializationT extends Serialization> Key parseKey(final SerializationT serializedKey, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        final ParserIndex index = new ParserIndex((Class)serializedKey.getClass(), serializedKey.getObjectIdentifier());
        if (!this.keyParserMap.containsKey(index)) {
            throw new GeneralSecurityException("No Key Parser for requested key type " + index + " available");
        }
        final KeyParser<SerializationT> parser = (KeyParser<SerializationT>)this.keyParserMap.get(index);
        return parser.parseKey(serializedKey, access);
    }
    
    public <KeyT extends Key, SerializationT extends Serialization> boolean hasSerializerForKey(final KeyT key, final Class<SerializationT> serializationClass) {
        final SerializerIndex index = new SerializerIndex((Class)key.getClass(), (Class)serializationClass);
        return this.keySerializerMap.containsKey(index);
    }
    
    public <KeyT extends Key, SerializationT extends Serialization> SerializationT serializeKey(final KeyT key, final Class<SerializationT> serializationClass, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        final SerializerIndex index = new SerializerIndex((Class)key.getClass(), (Class)serializationClass);
        if (!this.keySerializerMap.containsKey(index)) {
            throw new GeneralSecurityException("No Key serializer for " + index + " available");
        }
        final KeySerializer<KeyT, SerializationT> serializer = (KeySerializer<KeyT, SerializationT>)this.keySerializerMap.get(index);
        return serializer.serializeKey(key, access);
    }
    
    public <SerializationT extends Serialization> boolean hasParserForParameters(final SerializationT serializedParameters) {
        final ParserIndex index = new ParserIndex((Class)serializedParameters.getClass(), serializedParameters.getObjectIdentifier());
        return this.parametersParserMap.containsKey(index);
    }
    
    public <SerializationT extends Serialization> Parameters parseParameters(final SerializationT serializedParameters) throws GeneralSecurityException {
        final ParserIndex index = new ParserIndex((Class)serializedParameters.getClass(), serializedParameters.getObjectIdentifier());
        if (!this.parametersParserMap.containsKey(index)) {
            throw new GeneralSecurityException("No Parameters Parser for requested key type " + index + " available");
        }
        final ParametersParser<SerializationT> parser = (ParametersParser<SerializationT>)this.parametersParserMap.get(index);
        return parser.parseParameters(serializedParameters);
    }
    
    public <ParametersT extends Parameters, SerializationT extends Serialization> boolean hasSerializerForParameters(final ParametersT parameters, final Class<SerializationT> serializationClass) {
        final SerializerIndex index = new SerializerIndex((Class)parameters.getClass(), (Class)serializationClass);
        return this.parametersSerializerMap.containsKey(index);
    }
    
    public <ParametersT extends Parameters, SerializationT extends Serialization> SerializationT serializeParameters(final ParametersT parameters, final Class<SerializationT> serializationClass) throws GeneralSecurityException {
        final SerializerIndex index = new SerializerIndex((Class)parameters.getClass(), (Class)serializationClass);
        if (!this.parametersSerializerMap.containsKey(index)) {
            throw new GeneralSecurityException("No Key Format serializer for " + index + " available");
        }
        final ParametersSerializer<ParametersT, SerializationT> serializer = (ParametersSerializer<ParametersT, SerializationT>)this.parametersSerializerMap.get(index);
        return serializer.serializeParameters(parameters);
    }
    
    public static final class Builder
    {
        private final Map<SerializerIndex, KeySerializer<?, ?>> keySerializerMap;
        private final Map<ParserIndex, KeyParser<?>> keyParserMap;
        private final Map<SerializerIndex, ParametersSerializer<?, ?>> parametersSerializerMap;
        private final Map<ParserIndex, ParametersParser<?>> parametersParserMap;
        
        public Builder() {
            this.keySerializerMap = new HashMap<SerializerIndex, KeySerializer<?, ?>>();
            this.keyParserMap = new HashMap<ParserIndex, KeyParser<?>>();
            this.parametersSerializerMap = new HashMap<SerializerIndex, ParametersSerializer<?, ?>>();
            this.parametersParserMap = new HashMap<ParserIndex, ParametersParser<?>>();
        }
        
        public Builder(final SerializationRegistry registry) {
            this.keySerializerMap = new HashMap<SerializerIndex, KeySerializer<?, ?>>(registry.keySerializerMap);
            this.keyParserMap = new HashMap<ParserIndex, KeyParser<?>>(registry.keyParserMap);
            this.parametersSerializerMap = new HashMap<SerializerIndex, ParametersSerializer<?, ?>>(registry.parametersSerializerMap);
            this.parametersParserMap = new HashMap<ParserIndex, ParametersParser<?>>(registry.parametersParserMap);
        }
        
        @CanIgnoreReturnValue
        public <KeyT extends Key, SerializationT extends Serialization> Builder registerKeySerializer(final KeySerializer<KeyT, SerializationT> serializer) throws GeneralSecurityException {
            final SerializerIndex index = new SerializerIndex((Class)serializer.getKeyClass(), (Class)serializer.getSerializationClass());
            if (this.keySerializerMap.containsKey(index)) {
                final KeySerializer<?, ?> existingSerializer = this.keySerializerMap.get(index);
                if (!existingSerializer.equals(serializer) || !serializer.equals(existingSerializer)) {
                    throw new GeneralSecurityException("Attempt to register non-equal serializer for already existing object of type: " + index);
                }
            }
            else {
                this.keySerializerMap.put(index, serializer);
            }
            return this;
        }
        
        @CanIgnoreReturnValue
        public <SerializationT extends Serialization> Builder registerKeyParser(final KeyParser<SerializationT> parser) throws GeneralSecurityException {
            final ParserIndex index = new ParserIndex((Class)parser.getSerializationClass(), parser.getObjectIdentifier());
            if (this.keyParserMap.containsKey(index)) {
                final KeyParser<?> existingParser = this.keyParserMap.get(index);
                if (!existingParser.equals(parser) || !parser.equals(existingParser)) {
                    throw new GeneralSecurityException("Attempt to register non-equal parser for already existing object of type: " + index);
                }
            }
            else {
                this.keyParserMap.put(index, parser);
            }
            return this;
        }
        
        @CanIgnoreReturnValue
        public <ParametersT extends Parameters, SerializationT extends Serialization> Builder registerParametersSerializer(final ParametersSerializer<ParametersT, SerializationT> serializer) throws GeneralSecurityException {
            final SerializerIndex index = new SerializerIndex((Class)serializer.getParametersClass(), (Class)serializer.getSerializationClass());
            if (this.parametersSerializerMap.containsKey(index)) {
                final ParametersSerializer<?, ?> existingSerializer = this.parametersSerializerMap.get(index);
                if (!existingSerializer.equals(serializer) || !serializer.equals(existingSerializer)) {
                    throw new GeneralSecurityException("Attempt to register non-equal serializer for already existing object of type: " + index);
                }
            }
            else {
                this.parametersSerializerMap.put(index, serializer);
            }
            return this;
        }
        
        @CanIgnoreReturnValue
        public <SerializationT extends Serialization> Builder registerParametersParser(final ParametersParser<SerializationT> parser) throws GeneralSecurityException {
            final ParserIndex index = new ParserIndex((Class)parser.getSerializationClass(), parser.getObjectIdentifier());
            if (this.parametersParserMap.containsKey(index)) {
                final ParametersParser<?> existingParser = this.parametersParserMap.get(index);
                if (!existingParser.equals(parser) || !parser.equals(existingParser)) {
                    throw new GeneralSecurityException("Attempt to register non-equal parser for already existing object of type: " + index);
                }
            }
            else {
                this.parametersParserMap.put(index, parser);
            }
            return this;
        }
        
        public SerializationRegistry build() {
            return new SerializationRegistry(this, null);
        }
    }
    
    private static class SerializerIndex
    {
        private final Class<?> keyClass;
        private final Class<? extends Serialization> keySerializationClass;
        
        private SerializerIndex(final Class<?> keyClass, final Class<? extends Serialization> keySerializationClass) {
            this.keyClass = keyClass;
            this.keySerializationClass = keySerializationClass;
        }
        
        @Override
        public boolean equals(final Object o) {
            if (!(o instanceof SerializerIndex)) {
                return false;
            }
            final SerializerIndex other = (SerializerIndex)o;
            return other.keyClass.equals(this.keyClass) && other.keySerializationClass.equals(this.keySerializationClass);
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(this.keyClass, this.keySerializationClass);
        }
        
        @Override
        public String toString() {
            return this.keyClass.getSimpleName() + " with serialization type: " + this.keySerializationClass.getSimpleName();
        }
    }
    
    private static class ParserIndex
    {
        private final Class<? extends Serialization> keySerializationClass;
        private final Bytes serializationIdentifier;
        
        private ParserIndex(final Class<? extends Serialization> keySerializationClass, final Bytes serializationIdentifier) {
            this.keySerializationClass = keySerializationClass;
            this.serializationIdentifier = serializationIdentifier;
        }
        
        @Override
        public boolean equals(final Object o) {
            if (!(o instanceof ParserIndex)) {
                return false;
            }
            final ParserIndex other = (ParserIndex)o;
            return other.keySerializationClass.equals(this.keySerializationClass) && other.serializationIdentifier.equals(this.serializationIdentifier);
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(this.keySerializationClass, this.serializationIdentifier);
        }
        
        @Override
        public String toString() {
            return this.keySerializationClass.getSimpleName() + ", object identifier: " + this.serializationIdentifier;
        }
    }
}
