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

package com.hypixel.hytale.codec;

import org.bson.BsonValue;
import com.hypixel.hytale.codec.exception.CodecException;
import java.util.Optional;
import javax.annotation.Nullable;
import org.bson.BsonSerializationException;
import org.bson.BsonDocument;
import java.util.Objects;
import javax.annotation.Nonnull;

public class KeyedCodec<T>
{
    @Nonnull
    private final String key;
    @Nonnull
    private final Codec<T> codec;
    private final boolean required;
    
    public KeyedCodec(@Nonnull final String key, final Codec<T> codec) {
        this(key, codec, false);
    }
    
    public KeyedCodec(@Nonnull final String key, final Codec<T> codec, final boolean required) {
        this.key = Objects.requireNonNull(key, "key parameter can't be null");
        this.codec = Objects.requireNonNull(codec, "codec parameter can't be null");
        this.required = required;
        if (key.isEmpty()) {
            throw new IllegalArgumentException("Key must not be empty! Key: '" + key);
        }
        final char firstCharFromKey = key.charAt(0);
        if (Character.isLetter(firstCharFromKey) && !Character.isUpperCase(firstCharFromKey)) {
            throw new IllegalArgumentException("Key must start with an upper case character! Key: '" + key);
        }
    }
    
    @Deprecated
    public KeyedCodec(@Nonnull final String key, final Codec<T> codec, final boolean required, final boolean bypassCaseCheck) {
        this.key = Objects.requireNonNull(key, "key parameter can't be null");
        this.codec = Objects.requireNonNull(codec, "codec parameter can't be null");
        this.required = required;
        if (key.isEmpty()) {
            throw new IllegalArgumentException("Key must not be empty! Key: '" + key);
        }
        final char firstCharFromKey = key.charAt(0);
        if (!bypassCaseCheck && Character.isLetter(firstCharFromKey) && !Character.isUpperCase(firstCharFromKey)) {
            throw new IllegalArgumentException("Key must start with an upper case character! Key: '" + key);
        }
    }
    
    @Nonnull
    public String getKey() {
        return this.key;
    }
    
    @Deprecated
    public T getNow(final BsonDocument document) {
        return this.getNow(document, EmptyExtraInfo.EMPTY);
    }
    
    public T getNow(final BsonDocument document, @Nonnull final ExtraInfo extraInfo) {
        return this.get(document, extraInfo).orElseThrow(() -> new BsonSerializationException(this.key + " does not exist in document!"));
    }
    
    @Nullable
    @Deprecated
    public T getOrNull(final BsonDocument document) {
        return this.getOrNull(document, EmptyExtraInfo.EMPTY);
    }
    
    @Nullable
    public T getOrNull(final BsonDocument document, @Nonnull final ExtraInfo extraInfo) {
        return this.get(document, extraInfo).orElse(null);
    }
    
    @Nonnull
    @Deprecated
    public Optional<T> get(final BsonDocument document) {
        return this.get(document, EmptyExtraInfo.EMPTY);
    }
    
    @Nonnull
    public Optional<T> get(@Nullable final BsonDocument document, @Nonnull final ExtraInfo extraInfo) {
        extraInfo.pushKey(this.key);
        try {
            if (document == null) {
                return Optional.empty();
            }
            final BsonValue bsonValue = document.get(this.key);
            if (Codec.isNullBsonValue(bsonValue)) {
                return Optional.empty();
            }
            return Optional.ofNullable(this.decode(bsonValue, extraInfo));
        }
        catch (final Exception e) {
            throw new CodecException("Failed decode", document, extraInfo, e);
        }
        finally {
            extraInfo.popKey();
        }
    }
    
    @Nullable
    public T getOrDefault(@Nullable final BsonDocument document, @Nonnull final ExtraInfo extraInfo, final T def) {
        extraInfo.pushKey(this.key);
        try {
            if (document == null) {
                return def;
            }
            final BsonValue bsonValue = document.get(this.key);
            if (Codec.isNullBsonValue(bsonValue)) {
                return def;
            }
            return this.codec.decode(bsonValue, extraInfo);
        }
        catch (final Exception e) {
            throw new CodecException("Failed decode", document, extraInfo, e);
        }
        finally {
            extraInfo.popKey();
        }
    }
    
    @Nonnull
    public Optional<T> getAndInherit(@Nullable final BsonDocument document, final T parent, @Nonnull final ExtraInfo extraInfo) {
        extraInfo.pushKey(this.key);
        try {
            if (document == null) {
                return Optional.ofNullable((T)this.decodeAndInherit((BsonValue)null, (T)parent, extraInfo));
            }
            final BsonValue bsonValue = document.get(this.key);
            if (Codec.isNullBsonValue(bsonValue)) {
                return Optional.ofNullable((T)this.decodeAndInherit((BsonValue)null, (T)parent, extraInfo));
            }
            return Optional.ofNullable((T)this.decodeAndInherit(bsonValue, (T)parent, extraInfo));
        }
        catch (final Exception e) {
            throw new CodecException("Failed decode", document, extraInfo, e);
        }
        finally {
            extraInfo.popKey();
        }
    }
    
    @Deprecated
    public void put(@Nonnull final BsonDocument document, final T t) {
        this.put(document, t, EmptyExtraInfo.EMPTY);
    }
    
    public void put(@Nonnull final BsonDocument document, @Nullable final T t, @Nonnull final ExtraInfo extraInfo) {
        if (t != null) {
            try {
                document.put(this.key, this.encode(t, extraInfo));
            }
            catch (final Exception e) {
                throw new CodecException("Failed encode", t, extraInfo, e);
            }
        }
    }
    
    @Nullable
    protected T decode(final BsonValue bsonValue, @Nonnull final ExtraInfo extraInfo) {
        if (!this.required && Codec.isNullBsonValue(bsonValue)) {
            return null;
        }
        try {
            return this.codec.decode(bsonValue, extraInfo);
        }
        catch (final Exception e) {
            throw new CodecException("Failed to decode", bsonValue, extraInfo, e);
        }
    }
    
    @Nullable
    protected T decodeAndInherit(@Nullable final BsonValue bsonValue, final T parent, @Nonnull final ExtraInfo extraInfo) {
        if (!this.required && Codec.isNullBsonValue(bsonValue)) {
            return null;
        }
        try {
            if (bsonValue != null && bsonValue.isDocument() && this.codec instanceof InheritCodec) {
                return ((InheritCodec)this.codec).decodeAndInherit(bsonValue.asDocument(), parent, extraInfo);
            }
            return this.codec.decode(bsonValue, extraInfo);
        }
        catch (final Exception e) {
            throw new CodecException("Failed to decode", bsonValue, extraInfo, e);
        }
    }
    
    protected BsonValue encode(final T t, final ExtraInfo extraInfo) {
        return this.codec.encode(t, extraInfo);
    }
    
    @Nonnull
    public Codec<T> getChildCodec() {
        return this.codec;
    }
    
    public boolean isRequired() {
        return this.required;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "KeyedCodec{key='" + this.key + "', codec=" + String.valueOf(this.codec);
    }
}
