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

package com.hypixel.hytale.server.core.codec;

import com.hypixel.hytale.codec.schema.SchemaConvertable;
import com.hypixel.hytale.codec.schema.config.ArraySchema;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.schema.SchemaContext;
import java.io.IOException;
import com.hypixel.hytale.codec.util.RawJsonReader;
import org.bson.BsonArray;
import com.hypixel.hytale.codec.exception.CodecException;
import com.hypixel.hytale.common.map.WeightedMap;
import com.hypixel.hytale.codec.ExtraInfo;
import javax.annotation.Nonnull;
import org.bson.BsonValue;
import com.hypixel.hytale.codec.WrappedCodec;
import com.hypixel.hytale.common.map.IWeightedMap;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.common.map.IWeightedElement;

public class WeightedMapCodec<T extends IWeightedElement> implements Codec<IWeightedMap<T>>, WrappedCodec<T>
{
    private final Codec<T> codec;
    private final T[] emptyKeys;
    
    public WeightedMapCodec(final Codec<T> codec, final T[] emptyKeys) {
        this.codec = codec;
        this.emptyKeys = emptyKeys;
    }
    
    @Override
    public Codec<T> getChildCodec() {
        return this.codec;
    }
    
    @Override
    public IWeightedMap<T> decode(@Nonnull final BsonValue bsonValue, @Nonnull final ExtraInfo extraInfo) {
        final BsonArray array = bsonValue.asArray();
        final WeightedMap.Builder<T> mapBuilder = WeightedMap.builder(this.emptyKeys);
        mapBuilder.ensureCapacity(array.size());
        for (int i = 0; i < array.size(); ++i) {
            final BsonValue value = array.get(i);
            extraInfo.pushIntKey(i);
            try {
                final T element = this.codec.decode(value, extraInfo);
                mapBuilder.put(element, element.getWeight());
            }
            catch (final Exception e) {
                throw new CodecException("Failed to decode", value, extraInfo, e);
            }
            finally {
                extraInfo.popKey();
            }
        }
        return mapBuilder.build();
    }
    
    @Nonnull
    @Override
    public BsonValue encode(@Nonnull final IWeightedMap<T> map, final ExtraInfo extraInfo) {
        final BsonArray array = new BsonArray();
        map.forEach(element -> array.add(this.codec.encode((T)element, extraInfo)));
        return array;
    }
    
    @Override
    public IWeightedMap<T> decodeJson(@Nonnull final RawJsonReader reader, @Nonnull final ExtraInfo extraInfo) throws IOException {
        reader.expect('[');
        reader.consumeWhiteSpace();
        final WeightedMap.Builder<T> mapBuilder = WeightedMap.builder(this.emptyKeys);
        if (reader.tryConsume(']')) {
            return mapBuilder.build();
        }
        final int i = 0;
        while (true) {
            extraInfo.pushIntKey(i, reader);
            try {
                final T element = this.codec.decodeJson(reader, extraInfo);
                mapBuilder.put(element, element.getWeight());
            }
            catch (final Exception e) {
                throw new CodecException("Failed to decode", reader, extraInfo, e);
            }
            finally {
                extraInfo.popKey();
            }
            reader.consumeWhiteSpace();
            if (reader.tryConsumeOrExpect(']', ',')) {
                break;
            }
            reader.consumeWhiteSpace();
        }
        return mapBuilder.build();
    }
    
    @Nonnull
    @Override
    public Schema toSchema(@Nonnull final SchemaContext context) {
        final ArraySchema s = new ArraySchema();
        s.setTitle("WeightedMap");
        s.setItem(context.refDefinition(this.codec));
        return s;
    }
}
