package common.rng;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;

public class WeightedList<E extends RngItem> extends ArrayList<E> {
	protected boolean modified;
	protected int total;
	
	private static final WeightedList EMPTY_LIST = new WeightedList();
	
	public static <T extends RngItem> WeightedList<T> emptyList() {
		return EMPTY_LIST;
	}
	
	public WeightedList() {
		super();
	}
	
	public WeightedList(int initialCapacity) {
		super(initialCapacity);
	}
	
	public WeightedList(Collection<? extends E> c) {
		super(c);
		this.modified = true;
	}
	
	public WeightedList(E ... elems) {
		for(E elem : elems) {
			super.add(elem);
		}
		this.modified = true;
	}
	
	public E pick(Random rand) {
		if(this.modified) {
			this.modified = false;
			this.total = 0;
		    for(E item : this) {
		    	this.total += item.weight;
		    }
		}
		if(this.total <= 0)
            throw new IllegalStateException("Es befinden sich keine Elemente mit einem Wert in der Liste");
        int weight = rand.zrange(this.total);
        for(E item : this) {
            weight -= item.weight;
            if(weight < 0)
                return item;
        }
        return null;	
	}
	
	public boolean add(E e) {
		super.add(e);
		this.modified = true;
		return true;
	}
	
    public void add(int index, E element) {
        super.add(index, element);
		this.modified = true;
    }
	
	public void clear() {
		super.clear();
		this.modified = false;
		this.total = 0;
	}
	
    public E set(int index, E element) {
        E ret = super.set(index, element);
        if(ret != element)
        	this.modified = true;
        return ret;
    }
    
    public E remove(int index) {
    	E ret = super.remove(index);
    	this.modified = true;
    	return ret;
    }
    
    public boolean remove(Object o) {
        if(super.remove(o)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public boolean addAll(Collection<? extends E> c) {
    	if(super.addAll(c)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public boolean addAll(int index, Collection<? extends E> c) {
    	if(super.addAll(index, c)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public boolean removeAll(Collection<?> c) {
    	if(super.removeAll(c)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public boolean retainAll(Collection<?> c) {
    	if(super.retainAll(c)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public boolean removeIf(Predicate<? super E> filter) {
    	if(super.removeIf(filter)) {
        	this.modified = true;
        	return true;
        }
    	return false;
    }
    
    public void replaceAll(UnaryOperator<E> operator) {
        super.replaceAll(operator);
    	this.modified = true;
    }
    
    public void sort(Comparator<? super E> c) {
    	super.sort(c);
    	this.modified = true;
    }
}
