package speiger.src.collections.PACKAGE.sets;

import java.util.Collection;
import java.util.Collections;
#if TYPE_OBJECT
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.BiFunction;
#endif
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
#if JDK_FUNCTION
import java.util.function.PREDICATE;
#endif

import speiger.src.collections.PACKAGE.collections.BI_ITERATOR;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.functions.COMPARATOR;
import speiger.src.collections.PACKAGE.functions.CONSUMER;
#endif
import speiger.src.collections.ints.functions.consumer.BI_FROM_INT_CONSUMER;
import speiger.src.collections.objects.functions.consumer.BI_FROM_OBJECT_CONSUMER;
#if !JDK_FUNCTION
import speiger.src.collections.PACKAGE.functions.function.PREDICATE;
#endif
import speiger.src.collections.PACKAGE.functions.function.UNARY_OPERATOR;
import speiger.src.collections.PACKAGE.collections.COLLECTION;
import speiger.src.collections.PACKAGE.collections.ITERATOR;
import speiger.src.collections.objects.utils.ObjectArrays;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.utils.ITERATORS;
#endif
import speiger.src.collections.utils.SanityChecks;

/**
 * A Simple Type Specific AVL TreeSet implementation that reduces boxing/unboxing.
 * It is using a bit more memory then <a href="https://github.com/vigna/fastutil">FastUtil</a>,
 * but it saves a lot of Performance on the Optimized removal and iteration logic.
 * Which makes the implementation actually useable and does not get outperformed by Javas default implementation.
 * @Type(T)
 */
public class AVL_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements NAVIGABLE_SET KEY_GENERIC_TYPE
{
	/** The center of the Tree */
	protected transient Entry KEY_GENERIC_TYPE tree;
	/** The Lowest possible Node */
	protected transient Entry KEY_GENERIC_TYPE first;
	/** The Highest possible Node */
	protected transient Entry KEY_GENERIC_TYPE last;
	/** The amount of elements stored in the Set */
	protected int size = 0;
	/** The Sorter of the Tree */
	protected transient COMPARATOR KEY_GENERIC_TYPE comparator;
#if !TYPE_OBJECT
	/** the default return value for max searches */
	protected KEY_TYPE defaultMaxNotFound = CLASS_TYPE.MIN_VALUE;
	/** the default return value for min searches */
	protected KEY_TYPE defaultMinNotFound = CLASS_TYPE.MAX_VALUE;
#endif
	
	/**
	 * Default Constructor
	 */
	public AVL_TREE_SET() {
	}
	
	/**
	 * Constructor that allows to define the sorter
	 * @param comp the function that decides how the tree is sorted, can be null
	 */
	public AVL_TREE_SET(COMPARATOR KEY_GENERIC_TYPE comp) {
		comparator = comp;
	}
	
	/**
	 * Helper constructor that allow to create a set from an array
	 * @param array the elements that should be used
	 */
	public AVL_TREE_SET(KEY_TYPE[] array) {
		this(array, 0, array.length);
	}
	
	/**
	 * Helper constructor that allow to create a set from an array
	 * @param array the elements that should be used
	 * @param offset the starting index within the array
	 * @param length the amount of elements that are within the array
	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
	 */
	public AVL_TREE_SET(KEY_TYPE[] array, int offset, int length) {
		SanityChecks.checkArrayCapacity(array.length, offset, length);
		for(int i = 0;i<length;i++) add(array[offset+i]);
	}
	
	/**
	 * Helper constructor that allow to create a set from an array
	 * @param array the elements that should be used
	 * @param comp the sorter of the tree, can be null
	 */
	public AVL_TREE_SET(KEY_TYPE[] array, COMPARATOR KEY_GENERIC_TYPE comp) {
		this(array, 0, array.length, comp);
	}
	
	/**
	 * Helper constructor that allow to create a set from an array
	 * @param array the elements that should be used
	 * @param offset the starting index within the array
	 * @param length the amount of elements that are within the array
	 * @param comp the sorter of the tree, can be null
	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
	 */
	public AVL_TREE_SET(KEY_TYPE[] array, int offset, int length, COMPARATOR KEY_GENERIC_TYPE comp) {
		comparator = comp;
		SanityChecks.checkArrayCapacity(array.length, offset, length);
		for(int i = 0;i<length;i++) add(array[offset+i]);
	}
	
	/**
	 * A Helper constructor that allows to create a Set with exactly the same values as the provided SortedSet.
	 * @param sortedSet the set the elements should be added to the TreeSet
	 * @note this also includes the Comparator if present
	 */
	public AVL_TREE_SET(SORTED_SET KEY_GENERIC_TYPE sortedSet) {
		comparator = sortedSet.comparator();
		addAll(sortedSet);
	}
	
	/**
	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
	 * @param collection the set the elements should be added to the TreeSet
	 */
	@Primitive
	public AVL_TREE_SET(Collection<? extends CLASS_TYPE> collection) {
		addAll(collection);
	}
	
	/**
	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
	 * @param collection the set the elements should be added to the TreeSet
	 * @param comp the sorter of the tree, can be null
	 */
	@Primitive
	public AVL_TREE_SET(Collection<? extends CLASS_TYPE> collection, COMPARATOR KEY_GENERIC_TYPE comp) {
		comparator = comp;
		addAll(collection);
	}
	
	/**
	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
	 * @param collection the set the elements should be added to the TreeSet
	 */
	public AVL_TREE_SET(COLLECTION KEY_GENERIC_TYPE collection) {
		addAll(collection);
	}
	
	/**
	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
	 * @param collection the set the elements should be added to the TreeSet
	 * @param comp the sorter of the tree, can be null
	 */
	public AVL_TREE_SET(COLLECTION KEY_GENERIC_TYPE collection, COMPARATOR KEY_GENERIC_TYPE comp) {
		comparator = comp;
		addAll(collection);
	}
	
	/**
	 * A Helper constructor that allows to create a set from a iterator of an unknown size
	 * @param iterator the elements that should be added to the set
	 */
	public AVL_TREE_SET(Iterator<CLASS_TYPE> iterator) {
#if !TYPE_OBJECT
		this(ITERATORS.wrap(iterator));
#else
		while(iterator.hasNext()) add(iterator.next());
#endif
	}
	
	/**
	 * A Helper constructor that allows to create a set from a iterator of an unknown size
	 * @param iterator the elements that should be added to the set
	 * @param comp the sorter of the tree, can be null
	 */
	public AVL_TREE_SET(Iterator<CLASS_TYPE> iterator, COMPARATOR KEY_GENERIC_TYPE comp) {
#if !TYPE_OBJECT
		this(ITERATORS.wrap(iterator), comp);
#else
		comparator = comp;
		while(iterator.hasNext()) add(iterator.next());
#endif
	}
	
	/**
	 * A Helper constructor that allows to create a set from a iterator of an unknown size
	 * @param iterator the elements that should be added to the set
	 */
	public AVL_TREE_SET(ITERATOR KEY_GENERIC_TYPE iterator) {
		while(iterator.hasNext()) add(iterator.NEXT());
	}
	
	/**
	 * A Helper constructor that allows to create a set from a iterator of an unknown size
	 * @param iterator the elements that should be added to the set
	 * @param comp the sorter of the tree, can be null
	 */
	public AVL_TREE_SET(ITERATOR KEY_GENERIC_TYPE iterator, COMPARATOR KEY_GENERIC_TYPE comp) {
		comparator = comp;
		while(iterator.hasNext()) add(iterator.NEXT());
	}
	
#if !TYPE_OBJECT
	@Override
	public void setDefaultMaxValue(KEY_TYPE value) { defaultMaxNotFound = value; }
	@Override
	public KEY_TYPE getDefaultMaxValue() { return defaultMaxNotFound; }
	@Override
	public void setDefaultMinValue(KEY_TYPE value) { defaultMinNotFound = value; }
	@Override
	public KEY_TYPE getDefaultMinValue() { return defaultMinNotFound; }
	
#else
	/** only used for primitives 
	 * @return null 
	 */
	public CLASS_TYPE getDefaultMaxValue() { return null; }
	/** only used for primitives 
	 * @return null 
	 */
	public CLASS_TYPE getDefaultMinValue() { return null; }
	
#endif
	@Override
	public boolean add(KEY_TYPE o) {
#if TYPE_OBJECT
		validate(o);
#endif
		if(tree == null) {
			tree = first = last = new EntryBRACES(o, null);
			size++;
			return true;
		}
		int compare = 0;
		Entry KEY_GENERIC_TYPE parent = tree;
		while(true) {
			if((compare = compare(o, parent.key)) == 0) return false;
			if(compare < 0) {
				if(parent.left == null) break;
				parent = parent.left;
			}
			else if(compare > 0) {
				if(parent.right == null) break;
				parent = parent.right;
			}
		}
		Entry KEY_GENERIC_TYPE adding = new EntryBRACES(o, parent);
		if(compare < 0)  {
			parent.left = adding;
			if(parent == first)	first = adding;
		}
		else  {
			parent.right = adding;
			if(parent == last) last = adding;
		}
		fixAfterInsertion(adding);
		size++;
		return true;
	}
	
#if TYPE_OBJECT
	@Override
	public KEY_TYPE addOrGet(KEY_TYPE o) {
		validate(o);
		if(tree == null) {
			tree = first = last = new EntryBRACES(o, null);
			size++;
			return o;
		}
		int compare = 0;
		Entry KEY_GENERIC_TYPE parent = tree;
		while(true) {
			if((compare = compare(o, parent.key)) == 0) return parent.key;
			if(compare < 0) {
				if(parent.left == null) break;
				parent = parent.left;
			}
			else if(compare > 0) {
				if(parent.right == null) break;
				parent = parent.right;
			}
		}
		Entry KEY_GENERIC_TYPE adding = new EntryBRACES(o, parent);
		if(compare < 0)  {
			parent.left = adding;
			if(parent == first)	first = adding;
		}
		else  {
			parent.right = adding;
			if(parent == last) last = adding;
		}
		fixAfterInsertion(adding);
		size++;
		return o;
	}
	
#endif
	@Override
	public KEY_TYPE lower(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findLowerNode(e);
		return node != null ? node.key : getDefaultMinValue();
	}

	@Override
	public KEY_TYPE floor(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findFloorNode(e);
		return node != null ? node.key : getDefaultMinValue();
	}
	
	@Override
	public KEY_TYPE higher(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findHigherNode(e);
		return node != null ? node.key : getDefaultMaxValue();
	}

	@Override
	public KEY_TYPE ceiling(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findCeilingNode(e);
		return node != null ? node.key : getDefaultMaxValue();
	}
	
	#if !TYPE_OBJECT
	@Override
	public CLASS_TYPE lower(CLASS_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findLowerNode(e);
		return node != null ? node.key : null;
	}
	
	@Override
	public CLASS_TYPE floor(CLASS_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findFloorNode(e);
		return node != null ? node.key : null;
	}
	
	@Override
	public CLASS_TYPE higher(CLASS_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findHigherNode(e);
		return node != null ? node.key : null;
	}
	
	@Override
	public CLASS_TYPE ceiling(CLASS_TYPE e) {
		Entry KEY_GENERIC_TYPE node = findCeilingNode(e);
		return node != null ? node.key : null;
	}
	
#endif
	@Override
	public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) {
		Objects.requireNonNull(action);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			action.accept(entry.key);
		}
	}
	
	@Override
	public void forEachIndexed(BI_FROM_INT_CONSUMER KEY_GENERIC_TYPE action) {
		Objects.requireNonNull(action);
		int index = 0;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			action.accept(index++, entry.key);
		}
	}
	
	@Override
	public <E> void forEach(E input, BI_FROM_OBJECT_CONSUMER KSK_GENERIC_TYPE<E> action) {
		Objects.requireNonNull(action);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next())
			action.accept(input, entry.key);		
	}
	
	@Override
	public boolean matchesAny(PREDICATE KEY_GENERIC_TYPE filter) {
		Objects.requireNonNull(filter);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(filter.test(entry.key)) return true;
		}
		return false;
	}
	
	@Override
	public boolean matchesNone(PREDICATE KEY_GENERIC_TYPE filter) {
		Objects.requireNonNull(filter);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(filter.test(entry.key)) return false;
		}
		return true;
	}
	
	@Override
	public boolean matchesAll(PREDICATE KEY_GENERIC_TYPE filter) {
		Objects.requireNonNull(filter);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(!filter.test(entry.key)) return false;
		}
		return true;
	}
	
	@Override
	public KEY_TYPE findFirst(PREDICATE KEY_GENERIC_TYPE filter) {
		Objects.requireNonNull(filter);
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(filter.test(entry.key)) return entry.key;
		}
		return EMPTY_VALUE;
	}
	
#if !TYPE_OBJECT
	@Override
	public KEY_TYPE reduce(KEY_TYPE identity, UNARY_OPERATOR KEY_KEY_GENERIC_TYPE operator) {
		Objects.requireNonNull(operator);
		KEY_TYPE state = identity;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			state = operator.APPLY_VALUE(state, entry.key);
		}
		return state;
	}
	
#else
	@Override
	public <KEY_SPECIAL_TYPE> KEY_SPECIAL_TYPE reduce(KEY_SPECIAL_TYPE identity, BiFunction<KEY_SPECIAL_TYPE, KEY_TYPE, KEY_SPECIAL_TYPE> operator) {
		Objects.requireNonNull(operator);
		KEY_SPECIAL_TYPE state = identity;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			state = operator.APPLY_VALUE(state, entry.key);
		}
		return state;
	}
	
#endif
	@Override
	public KEY_TYPE reduce(UNARY_OPERATOR KEY_KEY_GENERIC_TYPE operator) {
		Objects.requireNonNull(operator);
		KEY_TYPE state = EMPTY_VALUE;
		boolean empty = true;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(empty) {
				empty = false;
				state = entry.key;
				continue;
			}
			state = operator.APPLY_VALUE(state, entry.key);
		}
		return state;
	}
	
	@Override
	public int count(PREDICATE KEY_GENERIC_TYPE filter) {
		Objects.requireNonNull(filter);
		int result = 0;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			if(filter.test(entry.key)) result++;
		}
		return result;
	}
	
	protected Entry KEY_GENERIC_TYPE findNode(KEY_TYPE o) {
		Entry KEY_GENERIC_TYPE node = tree;
		int compare;
		while(node != null) {
			if((compare = compare(o, node.key)) == 0) return node;
			if(compare < 0) node = node.left;
			else node = node.right;
		}
		return null;
	}
	
	protected Entry KEY_GENERIC_TYPE findLowerNode(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE entry = tree;
		while(entry != null) {
			if(compare(e, entry.key) > 0) {
				if(entry.right != null) entry = entry.right;
				else return entry;
			}
			else {
				if(entry.left != null) entry = entry.left;
				else {
					Entry KEY_GENERIC_TYPE parent = entry.parent;
					while(parent != null && parent.left == entry) {
						entry = parent;
						parent = parent.parent;
					}
					return parent;
				}
			}
		}
		return null;
	}
	
	protected Entry KEY_GENERIC_TYPE findFloorNode(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE entry = tree;
		int compare;
		while(entry != null) {
			if((compare = compare(e, entry.key)) > 0) {
				if(entry.right == null) break;
				entry = entry.right;
				continue;
			}
			else if(compare < 0) {
				if(entry.left != null) entry = entry.left;
				else {
					Entry KEY_GENERIC_TYPE parent = entry.parent;
					while(parent != null && parent.left == entry) {
						entry = parent;
						parent = parent.parent;
					}
					return parent;
				}
				continue;
			}
			break;
		}
		return entry;
	}
	
	protected Entry KEY_GENERIC_TYPE findCeilingNode(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE entry = tree;
		int compare;
		while(entry != null) {
			if((compare = compare(e, entry.key)) < 0) {
				if(entry.left == null) break;
				entry = entry.left;
				continue;
			}
			else if(compare > 0) {
				if(entry.right != null) entry = entry.right;
				else {
					Entry KEY_GENERIC_TYPE parent = entry.parent;
					while(parent != null && parent.right == entry) {
						entry = parent;
						parent = parent.parent;
					}
					return parent;
				}
				continue;
			}
			break;
		}
		return entry;
	}
	
	protected Entry KEY_GENERIC_TYPE findHigherNode(KEY_TYPE e) {
		Entry KEY_GENERIC_TYPE entry = tree;
		while(entry != null) {
			if(compare(e, entry.key) < 0) {
				if(entry.left != null) entry = entry.left;
				else return entry;
			}
			else {
				if(entry.right != null) entry = entry.right;
				else {
					Entry KEY_GENERIC_TYPE parent = entry.parent;
					while(parent != null && parent.right == entry) {
						entry = parent;
						parent = parent.parent;
					}
					return parent;
				}
			}
		}
		return null;
	}
	
#if !TYPE_OBJECT
	@Override
	public boolean contains(KEY_TYPE e) {
		return findNode(e) != null;
	}
	
#endif
	@Override
	public boolean contains(Object e) {
		return findNode(OBJ_TO_KEY(((CLASS_TYPE)e))) != null;
	}
	
	@Override
	public KEY_TYPE FIRST_KEY() {
		if(tree == null) throw new NoSuchElementException();
		return first.key;
	}
	
	@Override
	public KEY_TYPE LAST_KEY() {
		if(tree == null) throw new NoSuchElementException();
		return last.key;
	}
	
#if !TYPE_OBJECT
	@Override
	public boolean remove(KEY_TYPE o) {
		if(tree == null) return false;
		Entry KEY_GENERIC_TYPE entry = findNode(o);
		if(entry != null) {
			removeNode(entry);
			return true;
		}
		return false;
	}
	
#endif
	@Override
	public boolean remove(Object o) {
		if(tree == null) return false;
		Entry KEY_GENERIC_TYPE entry = findNode(OBJ_TO_KEY(((CLASS_TYPE)o)));
		if(entry != null) {
			removeNode(entry);
			return true;
		}
		return false;
	}
	
	@Override
	public KEY_TYPE POLL_FIRST_KEY() {
#if TYPE_OBJECT
		if(tree == null) return null;
#else
		if(tree == null) return getDefaultMinValue();
#endif
		KEY_TYPE value = first.key;
		removeNode(first);
		return value;
	}
	
	@Override
	public KEY_TYPE POLL_LAST_KEY() {
#if TYPE_OBJECT
		if(tree == null) return null;
#else
		if(tree == null) return getDefaultMaxValue();
#endif
		KEY_TYPE value = last.key;
		removeNode(last);
		return value;
	}
	
	@Override
	public int size() { return size; }
	
	@Override
	public void clear() {
		size = 0;
		first = null;
		last = null;
		tree = null;
	}
	
#if !TYPE_OBJECT
	@Override
	public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) {
		if(a == null || a.length < size()) a = new KEY_TYPE[size()];
		int index = 0;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			a[index++] = entry.key;
		}
		if (a.length > size) a[size] = EMPTY_KEY_VALUE;
		return a;
	}
	
#endif
	@Override
	@Deprecated
	public Object[] toArray() {
		if(isEmpty()) return ObjectArrays.EMPTY_ARRAY;
		Object[] obj = new Object[size()];
		int index = 0;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			obj[index++] = KEY_TO_OBJ(entry.key);
		}
		return obj;
	}
	
	@Override
	@Primitive
	public <E> E[] toArray(E[] a) {
		if(a == null) a = (E[])new Object[size()];
		else if(a.length < size()) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size());
		int index = 0;
		for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next()) {
			a[index++] = (E)KEY_TO_OBJ(entry.key);
		}
		if (a.length > size) a[size] = null;
		return a;
	}
	
	public AVL_TREE_SET KEY_GENERIC_TYPE copy() {
		AVL_TREE_SET KEY_GENERIC_TYPE set = new AVL_TREE_SETBRACES();
		set.size = size;
		if(tree != null) {
			set.tree = tree.copy();
			Entry KEY_GENERIC_TYPE lastFound = null;
			for(Entry KEY_GENERIC_TYPE entry = tree;entry != null;entry = entry.left) lastFound = entry;
			set.first = lastFound;
			lastFound = null;
			for(Entry KEY_GENERIC_TYPE entry = tree;entry != null;entry = entry.right) lastFound = entry;
			set.last = lastFound;
		}
		return set;
	}
	
	@Override
	public COMPARATOR KEY_GENERIC_TYPE comparator() { return comparator; }
	
	@Override
	public BI_ITERATOR KEY_GENERIC_TYPE iterator() { return new AscendingSetIterator(first); }
	
	@Override
	public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
		Entry KEY_GENERIC_TYPE entry = findNode(fromElement);
		return entry == null ? null : new AscendingSetIterator(entry);
	}
	
	@Override
	public BI_ITERATOR KEY_GENERIC_TYPE descendingIterator() { return new DescendingSetIterator(last); }
	
	@Override
	public NAVIGABLE_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, boolean fromInclusive, KEY_TYPE toElement, boolean toInclusive) {
		return new AscendingSubSetBRACES(this, false, fromElement, fromInclusive, false, toElement, toInclusive);
	}

	@Override
	public NAVIGABLE_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement, boolean inclusive) {
		return new AscendingSubSetBRACES(this, true, EMPTY_KEY_VALUE, true, false, toElement, inclusive);
	}

	@Override
	public NAVIGABLE_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement, boolean inclusive) {
		return new AscendingSubSetBRACES(this, false, fromElement, inclusive, true, EMPTY_KEY_VALUE, true);
	}
	
	@Override
	public NAVIGABLE_SET KEY_GENERIC_TYPE descendingSet() {
		return new DescendingSubSetBRACES(this, true, EMPTY_KEY_VALUE, true, true, EMPTY_KEY_VALUE, true);
	}
	
	protected void removeNode(Entry KEY_GENERIC_TYPE entry) {
		size--;
		if(entry.needsSuccessor()) {
			Entry KEY_GENERIC_TYPE successor = entry.next();
			entry.key = successor.key;
			entry = successor;
		}
		if(entry.previous() == null) first = entry.next();
		if(entry.next() == null) last = entry.previous();
		Entry KEY_GENERIC_TYPE replacement = entry.left != null ? entry.left : entry.right;
		if(replacement != null) {
			if(entry.replace(replacement)) tree = replacement;
			entry.left = entry.right = entry.parent = null;
			fixAfterDeletion(replacement);
		}
		else if(entry.parent == null) tree = first = last = null;
		else {
			fixAfterDeletion(entry);
			entry.replace(null);
			entry.parent = null;
		}
	}
	
	protected void validate(KEY_TYPE k) { compare(k, k); }
	protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);}
	
	/** From CLR */
	protected void rotateLeft(Entry KEY_GENERIC_TYPE entry) {
		if(entry != null) {
			Entry KEY_GENERIC_TYPE right = entry.right;
			entry.right = right.left;
			if(right.left != null) right.left.parent = entry;
			right.parent = entry.parent;
			if(entry.parent == null) tree = right;
			else if(entry.parent.left == entry) entry.parent.left = right;
			else entry.parent.right = right;
			right.left = entry;
			entry.parent = right;
			entry.updateHeight();
			right.updateHeight();
		}
	}
	
	/** From CLR */
	protected void rotateRight(Entry KEY_GENERIC_TYPE entry) {
		if(entry != null) {
			Entry KEY_GENERIC_TYPE left = entry.left;
			entry.left = left.right;
			if(left.right != null) left.right.parent = entry;
			left.parent = entry.parent;
			if(entry.parent == null) tree = left;
			else if(entry.parent.right == entry) entry.parent.right = left;
			else entry.parent.left = left;
			left.right = entry;
			entry.parent = left;
			entry.updateHeight();
			left.updateHeight();
		}
	}
	
	/** From CLR */
	protected void fixAfterInsertion(Entry KEY_GENERIC_TYPE entry) {
		while(entry != null) {
			entry.updateHeight();
			int balance = entry.getBalance();
			if(balance > 1) {
				int compare = entry.left.getBalance();
				if(compare > 0) rotateRight(entry);
				else if(compare < 0) {
					rotateLeft(entry.left);
					rotateRight(entry);
				}
			}
			else if(balance < -1) {
				int compare = entry.right.getBalance();
				if(compare < 0) rotateLeft(entry);
				else if(compare > 0) {
					rotateRight(entry.right);
					rotateLeft(entry);
				}
			}
			entry = entry.parent;
		}
	}
	
	/** From CLR */
	protected void fixAfterDeletion(Entry KEY_GENERIC_TYPE entry) {
		if(entry != null) {
			entry.updateHeight();
			int balance = entry.getBalance();
			if(balance > 1) {
				int subBalance = entry.left.getBalance();
				if(subBalance >= 0) rotateRight(entry);
				else {
					rotateLeft(entry.left);
					rotateRight(entry);
				}
			}
			else if(balance < -1)
			{
				int subBalance = entry.right.getBalance();
				if(subBalance <= 0) rotateLeft(entry);
				else {
					rotateRight(entry.right);
					rotateLeft(entry);
				}
			}
			entry = entry.parent;
		}
	}
	
	static class AscendingSubSet KEY_GENERIC_TYPE extends SubSet KEY_GENERIC_TYPE
	{
		public AscendingSubSet(AVL_TREE_SET KEY_GENERIC_TYPE set, boolean fromStart, KEY_TYPE lo, boolean loInclusive, boolean toEnd, KEY_TYPE hi, boolean hiInclusive)
		{
			super(set, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
		}
		
		@Override
		public COMPARATOR KEY_GENERIC_TYPE comparator() { return set.comparator(); }
		
		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, boolean fromInclusive, KEY_TYPE toElement, boolean toInclusive)
		{
			if(!inRange(fromElement, fromInclusive)) throw new IllegalArgumentException("fromElement out of range");
			if(!inRange(toElement, toInclusive)) throw new IllegalArgumentException("toElement out of range");
			return new AscendingSubSetBRACES(set, false, fromElement, fromInclusive, false, toElement, toInclusive);
		}
		
		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement, boolean inclusive)
		{
			if(!inRange(toElement, inclusive)) throw new IllegalArgumentException("toElement out of range");
			return new AscendingSubSetBRACES(set, fromStart, lo, loInclusive, false, toElement, inclusive);
		}

		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement, boolean inclusive)
		{
			if(!inRange(fromElement, inclusive)) throw new IllegalArgumentException("fromElement out of range");
			return new AscendingSubSetBRACES(set, false, fromElement, inclusive, toEnd, hi, hiInclusive);
		}
		
		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE iterator()
		{
			return new AscendingSubSetIterator(absLowest(), absHighFence(), absLowFence());
		}
		
		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement)
		{
			return new AscendingSubSetIterator(absLower(fromElement), absHighFence(), absLowFence());
		}
		
		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE descendingIterator()
		{
			return new DescendingSubSetIterator(absHighest(), absLowFence(), absHighFence());
		}

		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE descendingSet()
		{
			if(inverse == null) inverse = new DescendingSubSetBRACES(set, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
			return inverse;
		}
		
		@Override
		protected Entry KEY_GENERIC_TYPE subLowest() { return absLowest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE subHighest() { return absHighest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE subCeiling(KEY_TYPE key) { return absCeiling(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subHigher(KEY_TYPE key) { return absHigher(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subFloor(KEY_TYPE key) { return absFloor(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subLower(KEY_TYPE key) { return absLower(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE start() { return absLowest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE next(Entry KEY_GENERIC_TYPE entry) { return entry.next(); }
	}
	
	static class DescendingSubSet KEY_GENERIC_TYPE extends SubSet KEY_GENERIC_TYPE
	{
		COMPARATOR KEY_GENERIC_TYPE comparator;
		
		public DescendingSubSet(AVL_TREE_SET KEY_GENERIC_TYPE set, boolean fromStart, KEY_TYPE lo, boolean loInclusive, boolean toEnd, KEY_TYPE hi, boolean hiInclusive)
		{
			super(set, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
#if TYPE_OBJECT
			comparator = Collections.reverseOrder(set.comparator());
#else
			comparator = set.comparator() == null ? COMPARATOR.of(Collections.reverseOrder()) : set.comparator().reversed();
#endif
		}
		
		@Override
		public COMPARATOR KEY_GENERIC_TYPE comparator() { return comparator; }
		
		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, boolean fromInclusive, KEY_TYPE toElement, boolean toInclusive) {
			if(!inRange(fromElement, fromInclusive)) throw new IllegalArgumentException("fromElement out of range");
			if(!inRange(toElement, toInclusive)) throw new IllegalArgumentException("toElement out of range");
			return new DescendingSubSetBRACES(set, false, toElement, toInclusive, false, fromElement, fromInclusive);
		}
		
		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement, boolean inclusive)
		{
			if(!inRange(toElement, inclusive)) throw new IllegalArgumentException("toElement out of range");
			return new DescendingSubSetBRACES(set, false, toElement, inclusive, toEnd, hi, hiInclusive);
		}

		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement, boolean inclusive) {
			if(!inRange(fromElement, inclusive)) throw new IllegalArgumentException("fromElement out of range");
			return new DescendingSubSetBRACES(set, fromStart, lo, loInclusive, false, fromElement, inclusive);
		}

		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE iterator() {
			return new DescendingSubSetIterator(absHighest(), absLowFence(), absHighFence());
		}

		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE descendingIterator() {
			return new AscendingSubSetIterator(absLowest(), absHighFence(), absLowFence());
		}

		@Override
		public NAVIGABLE_SET KEY_GENERIC_TYPE descendingSet() {
			if(inverse == null) inverse = new AscendingSubSetBRACES(set, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
			return inverse;
		}
		
		@Override
		public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
			return new DescendingSubSetIterator(absHigher(fromElement), absLowFence(), absHighFence());
		}
		
		@Override
		protected Entry KEY_GENERIC_TYPE subLowest() { return absHighest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE subHighest() { return absLowest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE subCeiling(KEY_TYPE key) { return absFloor(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subHigher(KEY_TYPE key) { return absLower(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subFloor(KEY_TYPE key) { return absCeiling(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE subLower(KEY_TYPE key) { return absHigher(key); }
		@Override
		protected Entry KEY_GENERIC_TYPE start() { return absHighest(); }
		@Override
		protected Entry KEY_GENERIC_TYPE next(Entry KEY_GENERIC_TYPE entry) { return entry.previous(); }
	}
	
	static abstract class SubSet KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements NAVIGABLE_SET KEY_GENERIC_TYPE
	{
		final AVL_TREE_SET KEY_GENERIC_TYPE set;
		final KEY_TYPE lo, hi;
		final boolean fromStart, toEnd;
		final boolean loInclusive, hiInclusive;
		NAVIGABLE_SET KEY_GENERIC_TYPE inverse;
		
		public SubSet(AVL_TREE_SET KEY_GENERIC_TYPE set, boolean fromStart, KEY_TYPE lo, boolean loInclusive, boolean toEnd, KEY_TYPE hi, boolean hiInclusive)
		{
			this.set = set;
			this.lo = lo;
			this.hi = hi;
			this.fromStart = fromStart;
			this.toEnd = toEnd;
			this.loInclusive = loInclusive;
			this.hiInclusive = hiInclusive;
		}
		
#if !TYPE_OBJECT
		@Override
		public void setDefaultMaxValue(KEY_TYPE value) { set.setDefaultMaxValue(value); }
		@Override
		public KEY_TYPE getDefaultMaxValue() { return set.getDefaultMaxValue(); }
		@Override
		public void setDefaultMinValue(KEY_TYPE value) { set.setDefaultMinValue(value); }
		@Override
		public KEY_TYPE getDefaultMinValue() { return set.getDefaultMinValue(); }
#else
		public KEY_TYPE getDefaultMaxValue() { return null; }
		public KEY_TYPE getDefaultMinValue() { return null; }
#endif
		@Override
		public abstract	BI_ITERATOR KEY_GENERIC_TYPE iterator();
		
		boolean tooLow(KEY_TYPE key) {
			if (!fromStart) {
				int c = set.compare(key, lo);
				if (c < 0 || (c == 0 && !loInclusive)) return true;
			}
			return false;
		}
		
		boolean tooHigh(KEY_TYPE key) {
			if (!toEnd) {
				int c = set.compare(key, hi);
				if (c > 0 || (c == 0 && !hiInclusive)) return true;
			}
			return false;
		}
		
		boolean inRange(KEY_TYPE key) { return !tooLow(key) && !tooHigh(key); }
		boolean inClosedRange(KEY_TYPE key) { return (fromStart || set.compare(key, lo) >= 0) && (toEnd || set.compare(hi, key) >= 0); }
		boolean inRange(KEY_TYPE key, boolean inclusive) { return inclusive ? inRange(key) : inClosedRange(key); }
		
		protected abstract Entry KEY_GENERIC_TYPE subLowest();
		protected abstract Entry KEY_GENERIC_TYPE subHighest();
		protected abstract Entry KEY_GENERIC_TYPE subCeiling(KEY_TYPE key);
		protected abstract Entry KEY_GENERIC_TYPE subHigher(KEY_TYPE key);
		protected abstract Entry KEY_GENERIC_TYPE subFloor(KEY_TYPE key);
		protected abstract Entry KEY_GENERIC_TYPE subLower(KEY_TYPE key);
		protected KEY_TYPE lowKeyOrNull(Entry KEY_GENERIC_TYPE entry) { return entry == null ? getDefaultMinValue() : entry.key; }
		protected KEY_TYPE highKeyOrNull(Entry KEY_GENERIC_TYPE entry) { return entry == null ? getDefaultMaxValue() : entry.key; }
		protected abstract Entry KEY_GENERIC_TYPE start();
		protected abstract Entry KEY_GENERIC_TYPE next(Entry KEY_GENERIC_TYPE entry);
		
		final Entry KEY_GENERIC_TYPE absLowest() {
			Entry KEY_GENERIC_TYPE e = (fromStart ? set.first : (loInclusive ? set.findCeilingNode(lo) : set.findHigherNode(lo)));
			return (e == null || tooHigh(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absHighest() {
			Entry KEY_GENERIC_TYPE e = (toEnd ? set.last : (hiInclusive ? set.findFloorNode(hi) : set.findLowerNode(hi)));
			return (e == null || tooLow(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absCeiling(KEY_TYPE key) {
			if (tooLow(key)) return absLowest();
			Entry KEY_GENERIC_TYPE e = set.findCeilingNode(key);
			return (e == null || tooHigh(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absHigher(KEY_TYPE key) {
			if (tooLow(key)) return absLowest();
			Entry KEY_GENERIC_TYPE e = set.findHigherNode(key);
			return (e == null || tooHigh(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absFloor(KEY_TYPE key) {
			if (tooHigh(key)) return absHighest();
			Entry KEY_GENERIC_TYPE e = set.findFloorNode(key);
			return (e == null || tooLow(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absLower(KEY_TYPE key) {
			if (tooHigh(key)) return absHighest();
			Entry KEY_GENERIC_TYPE e = set.findLowerNode(key);
			return (e == null || tooLow(e.key)) ? null : e;
		}
		
		final Entry KEY_GENERIC_TYPE absHighFence() { return (toEnd ? null : (hiInclusive ? set.findHigherNode(hi) : set.findCeilingNode(hi))); }
		final Entry KEY_GENERIC_TYPE absLowFence() { return (fromStart ? null : (loInclusive ? set.findLowerNode(lo) : set.findFloorNode(lo))); }
		
		@Override
		public boolean add(KEY_TYPE o) {
			if(!inRange(o)) throw new IllegalArgumentException("Key is out of range");
			return set.add(o);
		}
		
#if !TYPE_OBJECT
		@Override
		public boolean contains(KEY_TYPE e) {
			return inRange(e) && set.contains(e);
		}
		
		@Override
		public boolean remove(KEY_TYPE o) {
			return inRange(o) && set.remove(o);
		}
		
#endif
		@Override
		public boolean contains(Object e) {
			KEY_TYPE o = OBJ_TO_KEY(((CLASS_TYPE)e));
			return inRange(o) && set.contains(o);
		}
	
		@Override
		public boolean remove(Object e) {
			KEY_TYPE o = OBJ_TO_KEY(((CLASS_TYPE)e));
			return inRange(o) && set.remove(o);
		}
		
		@Override
		public boolean isEmpty() {
			if(fromStart && toEnd) return set.isEmpty();
            Entry KEY_GENERIC_TYPE n = absLowest();
            return n == null || tooHigh(n.key);
		}
		
		@Override
		public int size() {
			if(fromStart && toEnd) return set.size();
			int i = 0;
			for(ITERATOR KEY_GENERIC_TYPE iter = iterator();iter.hasNext();iter.NEXT(),i++);
			return i;
		}
		
		@Override
		public KEY_TYPE lower(KEY_TYPE e) {
			return lowKeyOrNull(subLower(e));
		}
		
		@Override
		public KEY_TYPE floor(KEY_TYPE e) {
			return lowKeyOrNull(subFloor(e));
		}
		
		@Override
		public KEY_TYPE ceiling(KEY_TYPE e) {
			return highKeyOrNull(subCeiling(e));
		}
		
		@Override
		public KEY_TYPE higher(KEY_TYPE e) {
			return highKeyOrNull(subHigher(e));
		}
		
#if !TYPE_OBJECT
		@Override
		@Deprecated
		public CLASS_TYPE lower(CLASS_TYPE e) {
			Entry KEY_GENERIC_TYPE entry = subLower(e);
			return entry == null ? null : KEY_TO_OBJ(entry.key);
		}
		
		@Override
		@Deprecated
		public CLASS_TYPE floor(CLASS_TYPE e) {
			Entry KEY_GENERIC_TYPE entry = subFloor(e);
			return entry == null ? null : KEY_TO_OBJ(entry.key);
		}
		
		@Override
		@Deprecated
		public CLASS_TYPE ceiling(CLASS_TYPE e) {
			Entry KEY_GENERIC_TYPE entry = subCeiling(e);
			return entry == null ? null : KEY_TO_OBJ(entry.key);
		}
		
		@Override
		@Deprecated
		public CLASS_TYPE higher(CLASS_TYPE e) {
			Entry KEY_GENERIC_TYPE entry = subHigher(e);
			return entry == null ? null : KEY_TO_OBJ(entry.key);
		}
		
#endif
		@Override
		public KEY_TYPE POLL_FIRST_KEY() {
			Entry KEY_GENERIC_TYPE entry = subLowest();
			if(entry != null) {
				KEY_TYPE result = entry.key;
				set.removeNode(entry);
				return result;
			}
			return getDefaultMinValue();
		}
		
		@Override
		public KEY_TYPE POLL_LAST_KEY() {
			Entry KEY_GENERIC_TYPE entry = subHighest();
			if(entry != null) {
				KEY_TYPE result = entry.key;
				set.removeNode(entry);
				return result;
			}
			return getDefaultMaxValue();
		}
		
		@Override
		public KEY_TYPE FIRST_KEY() {
			Entry KEY_GENERIC_TYPE entry = subLowest();
			if(entry == null) throw new NoSuchElementException();
			return entry.key;
		}
		
		@Override
		public KEY_TYPE LAST_KEY() {
			Entry KEY_GENERIC_TYPE entry = subHighest();
			if(entry == null) throw new NoSuchElementException();
			return entry.key;
		}
		
		@Override
		public SubSet KEY_GENERIC_TYPE copy() { throw new UnsupportedOperationException(); }
		
		@Override
		public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) {
			Objects.requireNonNull(action);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				action.accept(entry.key);
			}
		}
		
		@Override
		public void forEachIndexed(BI_FROM_INT_CONSUMER KEY_GENERIC_TYPE action) {
			Objects.requireNonNull(action);
			int index = 0;
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				action.accept(index++, entry.key);
			}
		}
		
		@Override
		public <E> void forEach(E input, BI_FROM_OBJECT_CONSUMER KSK_GENERIC_TYPE<E> action) {
			Objects.requireNonNull(action);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry))
				action.accept(input, entry.key);		
		}
		
		@Override
		public boolean matchesAny(PREDICATE KEY_GENERIC_TYPE filter) {
			Objects.requireNonNull(filter);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(filter.test(entry.key)) return true;
			}
			return false;
		}
		
		@Override
		public boolean matchesNone(PREDICATE KEY_GENERIC_TYPE filter) {
			Objects.requireNonNull(filter);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(filter.test(entry.key)) return false;
			}
			return true;
		}
		
		@Override
		public boolean matchesAll(PREDICATE KEY_GENERIC_TYPE filter) {
			Objects.requireNonNull(filter);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(!filter.test(entry.key)) return false;
			}
			return true;
		}
		
#if !TYPE_OBJECT
		@Override
		public KEY_TYPE reduce(KEY_TYPE identity, UNARY_OPERATOR KEY_KEY_GENERIC_TYPE operator) {
			Objects.requireNonNull(operator);
			KEY_TYPE state = identity;
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				state = operator.APPLY_VALUE(state, entry.key);
			}
			return state;
		}
		
#else
		@Override
		public <KEY_SPECIAL_TYPE> KEY_SPECIAL_TYPE reduce(KEY_SPECIAL_TYPE identity, BiFunction<KEY_SPECIAL_TYPE, KEY_TYPE, KEY_SPECIAL_TYPE> operator) {
			Objects.requireNonNull(operator);
			KEY_SPECIAL_TYPE state = identity;
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				state = operator.APPLY_VALUE(state, entry.key);
			}
			return state;
		}
		
#endif
		@Override
		public KEY_TYPE reduce(UNARY_OPERATOR KEY_KEY_GENERIC_TYPE operator) {
			Objects.requireNonNull(operator);
			KEY_TYPE state = EMPTY_VALUE;
			boolean empty = true;
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(empty) {
					empty = false;
					state = entry.key;
					continue;
				}
				state = operator.APPLY_VALUE(state, entry.key);
			}
			return state;
		}
		
		@Override
		public KEY_TYPE findFirst(PREDICATE KEY_GENERIC_TYPE filter) {
			Objects.requireNonNull(filter);
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(filter.test(entry.key)) return entry.key;
			}
			return EMPTY_VALUE;
		}
		
		@Override
		public int count(PREDICATE KEY_GENERIC_TYPE filter) {
			Objects.requireNonNull(filter);
			int result = 0;
			for(Entry KEY_GENERIC_TYPE entry = start();entry != null && inRange(entry.key);entry = next(entry)) {
				if(filter.test(entry.key)) result++;
			}
			return result;
		}
		
		class AscendingSubSetIterator implements BI_ITERATOR KEY_GENERIC_TYPE
		{
			Entry KEY_GENERIC_TYPE lastReturned;
			Entry KEY_GENERIC_TYPE next;
			Entry KEY_GENERIC_TYPE previous;
			boolean forwards = false;
			boolean unboundForwardFence;
			boolean unboundBackwardFence;
			KEY_TYPE forwardFence;
			KEY_TYPE backwardFence;
			
			public AscendingSubSetIterator(Entry KEY_GENERIC_TYPE first, Entry KEY_GENERIC_TYPE forwardFence, Entry KEY_GENERIC_TYPE backwardFence)
			{
				next = first;
				previous = first == null ? null : first.previous();
				this.forwardFence = forwardFence == null ? EMPTY_KEY_VALUE : forwardFence.key;
				this.backwardFence = backwardFence == null ? EMPTY_KEY_VALUE : backwardFence.key;
				unboundForwardFence = forwardFence == null;
				unboundBackwardFence = backwardFence == null;
			}
			
			@Override
			public boolean hasNext() {
                return next != null && (unboundForwardFence || next.key != forwardFence);
			}
			
			@Override
			public KEY_TYPE NEXT() {
				if(!hasNext()) throw new NoSuchElementException();
				lastReturned = next;
				previous = next;
				KEY_TYPE result = next.key;
				next = next.next();
				forwards = true;
				return result;
			}
			
			@Override
			public boolean hasPrevious() {
                return previous != null && (unboundBackwardFence || previous.key != backwardFence);
			}
			
			@Override
			public KEY_TYPE PREVIOUS() {
				if(!hasPrevious()) throw new NoSuchElementException();
				lastReturned = previous;
				next = previous;
				KEY_TYPE result = previous.key;
				previous = previous.previous();
				forwards = false;
				return result;
			}
			
			@Override
			public void remove() {
				if(lastReturned == null) throw new IllegalStateException();
				if(previous == lastReturned) previous = previous.previous();
				if(next == lastReturned) next = next.next();
				if(forwards && lastReturned.needsSuccessor()) next = lastReturned;
				set.removeNode(lastReturned);
				lastReturned = null;
			}
		}
		
		class DescendingSubSetIterator implements BI_ITERATOR KEY_GENERIC_TYPE
		{
			Entry KEY_GENERIC_TYPE lastReturned;
			Entry KEY_GENERIC_TYPE next;
			Entry KEY_GENERIC_TYPE previous;
			boolean forwards = false;
			boolean unboundForwardFence;
			boolean unboundBackwardFence;
			KEY_TYPE forwardFence;
			KEY_TYPE backwardFence;
			
			public DescendingSubSetIterator(Entry KEY_GENERIC_TYPE first, Entry KEY_GENERIC_TYPE forwardFence, Entry KEY_GENERIC_TYPE backwardFence)
			{
				next = first;
				previous = first == null ? null : first.next();
				this.forwardFence = forwardFence == null ? EMPTY_KEY_VALUE : forwardFence.key;
				this.backwardFence = backwardFence == null ? EMPTY_KEY_VALUE : backwardFence.key;
				unboundForwardFence = forwardFence == null;
				unboundBackwardFence = backwardFence == null;
			}
			
			@Override
			public boolean hasNext() {
                return next != null && (unboundForwardFence || next.key != forwardFence);
			}
			
			@Override
			public KEY_TYPE NEXT() {
				if(!hasNext()) throw new NoSuchElementException();
				lastReturned = next;
				previous = next;
				KEY_TYPE result = next.key;
				next = next.previous();
				forwards = false;
				return result;
			}
			
			@Override
			public boolean hasPrevious() {
                return previous != null && (unboundBackwardFence || previous.key != backwardFence);
			}
			
			@Override
			public KEY_TYPE PREVIOUS() {
				if(!hasPrevious()) throw new NoSuchElementException();
				lastReturned = previous;
				next = previous;
				KEY_TYPE result = previous.key;
				previous = previous.next();
				forwards = true;
				return result;
			}
			
			@Override
			public void remove() {
				if(lastReturned == null) throw new IllegalStateException();
				if(previous == lastReturned) previous = previous.next();
				if(next == lastReturned) next = next.previous();
				if(forwards && lastReturned.needsSuccessor()) next = lastReturned;
				set.removeNode(lastReturned);
				lastReturned = null;
			}
		}
	}
	
	class AscendingSetIterator implements BI_ITERATOR KEY_GENERIC_TYPE
	{
		Entry KEY_GENERIC_TYPE lastReturned;
		Entry KEY_GENERIC_TYPE next;
		Entry KEY_GENERIC_TYPE previous;
		boolean forwards = false;
		
		public AscendingSetIterator(Entry KEY_GENERIC_TYPE first)
		{
			next = first;
			previous = first == null ? null : first.previous();
		}
		
		@Override
		public boolean hasNext() {
            return next != null;
		}
		
		@Override
		public KEY_TYPE NEXT() {
			if(!hasNext()) throw new NoSuchElementException();
			lastReturned = next;
			previous = next;
			KEY_TYPE result = next.key;
			next = next.next();
			forwards = true;
			return result;
		}
		
		@Override
		public boolean hasPrevious() {
            return previous != null;
		}
		
		@Override
		public KEY_TYPE PREVIOUS() {
			if(!hasPrevious()) throw new NoSuchElementException();
			lastReturned = previous;
			next = previous;
			KEY_TYPE result = previous.key;
			previous = previous.previous();
			forwards = false;
			return result;
		}
		
		@Override
		public void remove() {
			if(lastReturned == null) throw new IllegalStateException();
			if(lastReturned == previous) previous = previous.previous();
			if(lastReturned == next) next = next.next();
			if(forwards && lastReturned.needsSuccessor()) next = lastReturned;
			removeNode(lastReturned);
			lastReturned = null;
		}
	}
	
	class DescendingSetIterator implements BI_ITERATOR KEY_GENERIC_TYPE
	{
		Entry KEY_GENERIC_TYPE lastReturned;
		Entry KEY_GENERIC_TYPE next;
		Entry KEY_GENERIC_TYPE previous;
		boolean forwards = false;

		public DescendingSetIterator(Entry KEY_GENERIC_TYPE first)
		{
			next = first;
			previous = first == null ? null : first.next();
		}
		
		@Override
		public boolean hasNext() {
            return next != null;
		}
		
		@Override
		public KEY_TYPE NEXT() {
			if(!hasNext()) throw new NoSuchElementException();
			lastReturned = next;
			previous = next;
			KEY_TYPE result = next.key;
			next = next.previous();
			forwards = false;
			return result;
		}
		
		@Override
		public boolean hasPrevious() {
            return previous != null;
		}
		
		@Override
		public KEY_TYPE PREVIOUS() {
			if(!hasPrevious()) throw new NoSuchElementException();
			lastReturned = previous;
			next = previous;
			KEY_TYPE result = previous.key;
			previous = previous.next();
			forwards = true;
			return result;
		}
		
		@Override
		public void remove() {
			if(lastReturned == null) throw new IllegalStateException();
			if(lastReturned == previous) previous = previous.next();
			if(lastReturned == next) next = next.previous();
			if(forwards && lastReturned.needsSuccessor()) next = lastReturned;
			removeNode(lastReturned);
			lastReturned = null;
		}
	}
	
	private static final class Entry KEY_GENERIC_TYPE
	{
		KEY_TYPE key;
		int state;
		Entry KEY_GENERIC_TYPE parent;
		Entry KEY_GENERIC_TYPE left;
		Entry KEY_GENERIC_TYPE right;
		
		Entry(KEY_TYPE key, Entry KEY_GENERIC_TYPE parent) {
			this.key = key;
			this.parent = parent;
		}
		
		Entry KEY_GENERIC_TYPE copy() {
			Entry KEY_GENERIC_TYPE entry = new EntryBRACES(key, null);
			entry.state = state;
			if(left != null) {
				Entry KEY_GENERIC_TYPE newLeft = left.copy();
				entry.left = newLeft;
				newLeft.parent = entry;
			}
			if(right != null) {
				Entry KEY_GENERIC_TYPE newRight = right.copy();
				entry.right = newRight;
				newRight.parent = entry;
			}
			return entry;
		}
		
		int getHeight() { return state; }
		
		void updateHeight() { state = (1 + Math.max(left == null ? -1 : left.getHeight(), right == null ? -1 : right.getHeight())); }
		
		int getBalance() { return (left == null ? -1 : left.getHeight()) - (right == null ? -1 : right.getHeight()); }
		
		boolean needsSuccessor() { return left != null && right != null; }
		
		boolean replace(Entry KEY_GENERIC_TYPE entry) {
			if(entry != null) entry.parent = parent;
			if(parent != null) {
				if(parent.left == this) parent.left = entry;
				else parent.right = entry;
			}
			return parent == null;
		}
		
		Entry KEY_GENERIC_TYPE next() {
			if(right != null) {
				Entry KEY_GENERIC_TYPE parent = right;
				while(parent.left != null) parent = parent.left;
				return parent;
			}
			Entry KEY_GENERIC_TYPE parent = this.parent;
			Entry KEY_GENERIC_TYPE control = this;
			while(parent != null && control == parent.right) {
				control = parent;
				parent = parent.parent;
			}
			return parent;
		}
		
		Entry KEY_GENERIC_TYPE previous() {
			if(left != null) {
				Entry KEY_GENERIC_TYPE parent = left;
				while(parent.right != null) parent = parent.right;
				return parent;
			}
			Entry KEY_GENERIC_TYPE parent = this.parent;
			Entry KEY_GENERIC_TYPE control = this;
			while(parent != null && control == parent.left) {
				control = parent;
				parent = parent.parent;
			}
			return parent;
		}
	}
}