import java.util.Collection;

/**
 * @param <T> the base type of this Bag
 * @author Mark Young (A00000000)
 */
public interface Bag<T> extends Collection<T> {

    /**
     * Remove an item from this Bag. The item to remove is at the discretion of
     * the implementation.
     *
     * @return an arbitrary item removed from this Bag
     */
    public T remove();

    /**
     * Count how many times the given item appears in this Bag. That is, count
     * each {@code e} such that {@code Objects.equals(anItem, e)}.
     *
     * @param anItem the item to count
     * @return how many times that item appears in this Bag
     */
    public int getFrequency(T anItem);
    
    /*
     * Some default implementations for methods. I don't know why Collection
     * doesn't give these itself!
     */
    
    @Override
    public default boolean addAll(Collection<? extends T> c) {
        int oldSize = size();
        for (var item : c) {
            add(item);
        }
        return oldSize != size();
    }
    
    @Override
    public default void clear() {
        while (!isEmpty()) {
            remove();
        }
    }
    
    @Override
    public default boolean containsAll(Collection<?> c) {
        for (var obj : c) {
            if (!contains(obj)) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public default boolean isEmpty() {
        return size() == 0;
    }
    
    @Override
    public default boolean removeAll(Collection<?> c) {
        int oldSize = size();
        for (var obj : c) {
            remove(obj);
        }
        return oldSize != size();
    }
    
    @Override
    public default boolean retainAll(Collection<?> c) {
        int oldSize = size();
        for (Object obj : toArray()) {
            if (!c.contains(obj)) {
                remove(obj);
            }
        }
        return oldSize != size();
    }

}
