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

package com.hypixel.hytale.codec.lookup;

import java.io.IOException;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.util.RawJsonReader;
import javax.annotation.Nonnull;
import com.hypixel.hytale.codec.builder.StringTreeMap;
import java.util.concurrent.locks.StampedLock;
import com.hypixel.hytale.codec.Codec;

public abstract class StringCodecMapCodec<T, C extends Codec<? extends T>> extends ACodecMapCodec<String, T, C>
{
    protected final StampedLock stampedLock;
    protected final StringTreeMap<C> stringTreeMap;
    
    public StringCodecMapCodec() {
        super(Codec.STRING);
        this.stampedLock = new StampedLock();
        this.stringTreeMap = new StringTreeMap<C>();
    }
    
    public StringCodecMapCodec(final boolean allowDefault) {
        super(Codec.STRING, allowDefault);
        this.stampedLock = new StampedLock();
        this.stringTreeMap = new StringTreeMap<C>();
    }
    
    public StringCodecMapCodec(final String id) {
        super(id, Codec.STRING);
        this.stampedLock = new StampedLock();
        this.stringTreeMap = new StringTreeMap<C>();
    }
    
    public StringCodecMapCodec(final String key, final boolean allowDefault) {
        super(key, Codec.STRING, allowDefault);
        this.stampedLock = new StampedLock();
        this.stringTreeMap = new StringTreeMap<C>();
    }
    
    public StringCodecMapCodec(final String key, final boolean allowDefault, final boolean encodeDefaultKey) {
        super(key, Codec.STRING, allowDefault, encodeDefaultKey);
        this.stampedLock = new StampedLock();
        this.stringTreeMap = new StringTreeMap<C>();
    }
    
    @Override
    public StringCodecMapCodec<T, C> register(@Nonnull final Priority priority, @Nonnull final String id, final Class<? extends T> aClass, final C codec) {
        final long lock = this.stampedLock.readLock();
        try {
            this.stringTreeMap.put(id, codec);
        }
        finally {
            this.stampedLock.unlockRead(lock);
        }
        return (StringCodecMapCodec)super.register(priority, id, aClass, codec);
    }
    
    @Override
    public void remove(final Class<? extends T> aClass) {
        final String id = (String)this.classToId.get(aClass);
        if (id == null) {
            return;
        }
        final long lock = this.stampedLock.readLock();
        try {
            this.stringTreeMap.remove(id);
        }
        finally {
            this.stampedLock.unlockRead(lock);
        }
        super.remove(aClass);
    }
    
    @Override
    public T decodeJson(@Nonnull final RawJsonReader reader, @Nonnull final ExtraInfo extraInfo) throws IOException {
        reader.mark();
        C codec = null;
        int distance = 0;
        if (RawJsonReader.seekToKey(reader, this.key)) {
            distance = reader.getMarkDistance();
            final long lock = this.stampedLock.readLock();
            try {
                final StringTreeMap<C> entry = this.stringTreeMap.findEntry(reader);
                codec = (C)((entry == null) ? null : ((C)entry.getValue()));
            }
            finally {
                this.stampedLock.unlockRead(lock);
            }
        }
        extraInfo.ignoreUnusedKey(this.key);
        try {
            if (codec != null) {
                reader.reset();
                return (T)codec.decodeJson(reader, extraInfo);
            }
            final C defaultCodec = this.getDefaultCodec();
            if (defaultCodec != null) {
                reader.reset();
                return (T)defaultCodec.decodeJson(reader, extraInfo);
            }
            if (distance == 0) {
                throw new UnknownIdException("No codec registered with for '" + this.key + "': null");
            }
            reader.skip(distance - reader.getMarkDistance());
            final String id = reader.readString();
            throw new UnknownIdException("No codec registered with for '" + this.key + "': " + id);
        }
        finally {
            extraInfo.popIgnoredUnusedKey();
        }
    }
}
