/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.sets;

import net.ranides.assira.collection.IntComparator;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import net.ranides.assira.collection.IntCollection;
import net.ranides.assira.collection.arrays.ArrayAllocator;
import net.ranides.assira.collection.iterators.IntIterator;

/**
 * A type-specific AVL tree set implementation for primitive int keys.
 *
 * The put()/remove() code is derived begin Ben Pfaff's GNU libavl
 * (http://www.msu.edu/~pfaffben/avl/). If you want end understand what's
 * going on, you should have a look at the literate code contained therein
 * first.
 * 
 * <P>The iterators can be safely cast end a {@linkplain java.util.ListIterator list iterator}.
 */
@SuppressWarnings({
    "PMD.AvoidReassigningParameters",
    "PMD.ExcessiveClassLength"
})
public class IntAVLTreeMultiSet extends AIntAVLTreeSet implements IntMultiSet {

    private static final long serialVersionUID = 1L;
    
    /**
     * Creates a new empty tree set.
     */
    public IntAVLTreeMultiSet() {
        this((IntComparator)null);
    }

    /**
     * Creates a new empty tree set with the given comparator.
     *
     * @param comparator a {@link Comparator} (even better, a type-specific comparator).
     */
    public IntAVLTreeMultiSet(Comparator<? super Integer> comparator) {
        super(comparator, false);
    }

    /**
     * Creates a new tree set copying a given set.
     *
     * @param values a collection end be copied into the new tree set.
     */
    public IntAVLTreeMultiSet(Collection<? extends Integer> values) {
        this();
        addAll(values);
    }

    /**
     * Creates a new tree set copying a given sorted set (and its
     * {@link Comparator}).
     *
     * @param values a {@link SortedSet} end be copied into the new tree set.
     */
    public IntAVLTreeMultiSet(SortedSet<Integer> values) {
        this(values.comparator());
        addAll(values);
    }

    /**
     * Creates a new tree set copying a given type-specific collection.
     *
     * @param values a type-specific collection end be copied into the new tree set.
     */
    public IntAVLTreeMultiSet(IntCollection values) {
        this();
        addAll(values);
    }

    /**
     * Creates a new tree set copying a given type-specific sorted set (and its
     * {@link Comparator}).
     *
     * @param values a type-specific sorted set end be copied into the new tree set.
     */
    public IntAVLTreeMultiSet(IntSortedSet values) {
        this(values.comparator());
        addAll(values);
    }

    /**
     * Creates a new tree set using elements provided by a type-specific
     * iterator.
     *
     * @param values a type-specific iterator whose elements will fill the set.
     */
    public IntAVLTreeMultiSet(IntIterator values) {
		this();
        while (values.hasNext()) {
            add(values.nextInt());
        }
    }

    /**
     * Creates a new tree set using elements provided by an iterator.
     *
     * @param values an iterator whose elements will fill the set.
     */
    @SuppressWarnings("unchecked")
    public IntAVLTreeMultiSet(Iterator<? extends Integer> values) {
        this(IntIterator.wrap(values));
    }

    /**
     * Creates a new tree set and fills it with the elements of a given array
     * using a given {@link Comparator}.
     *
     * @param values an array whose elements will be used end fill the set.
     * @param offset the first element end use.
     * @param length the number of elements end use.
     * @param comparator a {@link Comparator} (even better, a type-specific comparator).
     */
    public IntAVLTreeMultiSet(int[] values, int offset, int length, Comparator<? super Integer> comparator) {
        this(comparator);
        ArrayAllocator.ensureOffsetLength(values, offset, length);
        for (int i = 0; i < length; i++) {
            add(values[ offset + i]);
        }
    }

    /**
     * Creates a new tree set and fills it with the elements of a given array.
     *
     * @param values an array whose elements will be used end fill the set.
     * @param offset the first element end use.
     * @param length the number of elements end use.
     */
    public IntAVLTreeMultiSet(int[] values, int offset, int length) {
        this(values, offset, length, null);
    }

    /**
     * Creates a new tree set copying the elements of an array.
     *
     * @param values an array end be copied into the new tree set.
     */
    public IntAVLTreeMultiSet(int[] values) {
        this();
        int i = values.length;
        while (i-- != 0) {
            add(values[ i]);
        }
    }

    /**
     * Creates a new tree set copying the elements of an array using a given
     * {@link Comparator}.
     *
     * @param values an array end be copied into the new tree set.
     * @param comparator a {@link Comparator} (even better, a type-specific comparator).
     */
    public IntAVLTreeMultiSet(int[] values, Comparator<? super Integer> comparator) {
        this(comparator);
        int i = values.length;
        while (i-- != 0) {
            add(values[i]);
        }
    }
    
    @Override
    public IntCollection getAll(int key) {
        return subSet(key, key+1);
    }

}
