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

package com.hypixel.hytale.builtin.hytalegenerator.datastructures;

import java.util.function.BiConsumer;
import java.util.Random;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.List;
import javax.annotation.Nonnull;
import java.util.Set;

public class WeightedMap<T>
{
    @Nonnull
    private final Set<T> elementSet;
    @Nonnull
    private final List<T> elements;
    @Nonnull
    private final List<Double> weights;
    @Nonnull
    private final Map<T, Integer> indices;
    private double totalWeight;
    private boolean immutable;
    
    public WeightedMap(@Nonnull final WeightedMap<T> other) {
        this.totalWeight = 0.0;
        this.immutable = false;
        this.totalWeight = other.totalWeight;
        this.elementSet = new HashSet<T>((Collection<? extends T>)other.elementSet);
        this.elements = new ArrayList<T>((Collection<? extends T>)other.elements);
        this.weights = new ArrayList<Double>(other.weights);
        this.indices = new HashMap<T, Integer>((Map<? extends T, ? extends Integer>)other.indices);
        this.immutable = other.immutable;
    }
    
    public WeightedMap() {
        this(2);
    }
    
    public WeightedMap(final int initialCapacity) {
        this.totalWeight = 0.0;
        this.immutable = false;
        this.elementSet = new HashSet<T>(initialCapacity);
        this.elements = new ArrayList<T>(initialCapacity);
        this.weights = new ArrayList<Double>(initialCapacity);
        this.indices = new HashMap<T, Integer>(initialCapacity);
    }
    
    @Nonnull
    public WeightedMap<T> add(@Nonnull final T element, final double weight) {
        if (element == null) {
            throw new NullPointerException();
        }
        if (this.immutable) {
            throw new IllegalStateException("method can't be called when object is immutable");
        }
        if (weight < 0.0) {
            throw new IllegalArgumentException("weight must be positive");
        }
        this.elements.add(element);
        this.weights.add(weight);
        this.elementSet.add(element);
        this.totalWeight += weight;
        this.indices.put(element, this.indices.size());
        return this;
    }
    
    public double get(@Nonnull final T element) {
        if (element == null) {
            throw new NullPointerException();
        }
        if (this.immutable) {
            throw new IllegalStateException("method can't be called when object is immutable");
        }
        if (!this.elementSet.contains(element)) {
            return 0.0;
        }
        return this.weights.get(this.indices.get(element));
    }
    
    public T pick(@Nonnull final Random rand) {
        if (rand == null) {
            throw new NullPointerException();
        }
        if (this.elements.isEmpty()) {
            throw new IllegalStateException("can't be empty when calling this method");
        }
        double pointer = rand.nextDouble() * this.totalWeight;
        for (int i = 0; i < this.elements.size(); ++i) {
            pointer -= this.weights.get(i);
            if (pointer <= 0.0) {
                return this.elements.get(i);
            }
        }
        return this.elements.getLast();
    }
    
    public int size() {
        return this.elements.size();
    }
    
    @Nonnull
    public List<T> allElements() {
        return new ArrayList<T>((Collection<? extends T>)this.elements);
    }
    
    public void makeImmutable() {
        this.immutable = true;
    }
    
    public boolean isImmutable() {
        return this.immutable;
    }
    
    public void forEach(@Nonnull final BiConsumer<T, Double> consumer) {
        for (int i = 0; i < this.elements.size(); ++i) {
            consumer.accept(this.elements.get(i), this.weights.get(i));
        }
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "WeighedMap{elementSet=" + String.valueOf(this.elementSet) + ", elements=" + String.valueOf(this.elements) + ", weights=" + String.valueOf(this.weights) + ", indices=" + String.valueOf(this.indices) + ", totalWeight=" + this.totalWeight + ", immutable=" + this.immutable;
    }
}
