/*
 * Copyright (C) 2002-2017 Sebastiano Vigna
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package PACKAGE;

import VALUE_PACKAGE.VALUE_COLLECTION;
import VALUE_PACKAGE.VALUE_ABSTRACT_COLLECTION;
import VALUE_PACKAGE.VALUE_ITERATOR;
import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;

#if KEYS_REFERENCE
import java.util.Comparator;
#endif

/** An abstract class providing basic methods for sorted maps implementing a type-specific interface. */

public abstract class ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC implements SORTED_MAP KEY_VALUE_GENERIC {

	private static final long serialVersionUID = -1773560792952436569L;

	protected ABSTRACT_SORTED_MAP() {}

	/** {@inheritDoc}
	 *
	 * <p>The view is backed by the sorted set returned by {@link java.util.Map#entrySet()}. Note that
	 * <em>no attempt is made at caching the result of this method</em>, as this would
	 * require adding some attributes that lightweight implementations would
	 * not need. Subclasses may easily override this policy by calling
	 * this method and caching the result, but implementors are encouraged to
	 * write more efficient ad-hoc implementations.
	 *
	 * @return a sorted set view of the keys of this map; it may be safely cast to a type-specific interface.
	 */
	@Override
	public SORTED_SET KEY_GENERIC keySet() {
		return new KeySet();
	}

	/** A wrapper exhibiting the keys of a map. */

	protected class KeySet extends ABSTRACT_SORTED_SET KEY_GENERIC {
		@Override
		public boolean contains(final KEY_TYPE k) { return containsKey(k); }

		@Override
		public int size() { return ABSTRACT_SORTED_MAP.this.size(); }

		@Override
		public void clear() { ABSTRACT_SORTED_MAP.this.clear(); }

		@Override
		public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return ABSTRACT_SORTED_MAP.this.comparator(); }

		@Override
		public KEY_GENERIC_TYPE FIRST() { return FIRST_KEY(); }

		@Override
		public KEY_GENERIC_TYPE LAST() { return LAST_KEY(); }

		@Override
		public SORTED_SET KEY_GENERIC headSet(final KEY_GENERIC_TYPE to) { return headMap(to).keySet(); }

		@Override
		public SORTED_SET KEY_GENERIC tailSet(final KEY_GENERIC_TYPE from) { return tailMap(from).keySet(); }

		@Override
		public SORTED_SET KEY_GENERIC subSet(final KEY_GENERIC_TYPE from, final KEY_GENERIC_TYPE to) { return subMap(from, to).keySet(); }

		@Override
		public KEY_BIDI_ITERATOR KEY_GENERIC iterator(final KEY_GENERIC_TYPE from) { return new KeySetIterator KEY_VALUE_GENERIC_DIAMOND(ENTRYSET().iterator(new BasicEntry KEY_VALUE_GENERIC_DIAMOND(from, VALUE_NULL))); }

		@Override
		public KEY_BIDI_ITERATOR KEY_GENERIC iterator() { return new KeySetIterator KEY_VALUE_GENERIC_DIAMOND(SORTED_MAPS.fastIterator(ABSTRACT_SORTED_MAP.this)); }
	}

	/** A wrapper exhibiting a map iterator as an iterator on keys.
	 *
	 * <p>To provide an iterator on keys, just create an instance of this
	 * class using the corresponding iterator on entries.
	 */

	protected static class KeySetIterator KEY_VALUE_GENERIC implements KEY_BIDI_ITERATOR KEY_GENERIC {
		protected final ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> i;

		public KeySetIterator(ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> i) {
			this.i = i;
		}

		@Override
		public KEY_GENERIC_TYPE NEXT_KEY() { return i.next().ENTRY_GET_KEY(); };

		@Override
		public KEY_GENERIC_TYPE PREV_KEY() { return i.previous().ENTRY_GET_KEY(); };

		@Override
		public boolean hasNext() { return i.hasNext(); }

		@Override
		public boolean hasPrevious() { return i.hasPrevious(); }
	}

	/** {@inheritDoc}
	 *
	 * <p>The view is backed by the sorted set returned by {@link java.util.Map#entrySet()}. Note that
	 * <em>no attempt is made at caching the result of this method</em>, as this would
	 * require adding some attributes that lightweight implementations would
	 * not need. Subclasses may easily override this policy by calling
	 * this method and caching the result, but implementors are encouraged to
	 * write more efficient ad-hoc implementations.
	 *
	 * @return a type-specific collection view of the values contained in this map.
	 */
	@Override
	public VALUE_COLLECTION VALUE_GENERIC values() {
		return new ValuesCollection();
	}

	/** A wrapper exhibiting the values of a map. */
	protected class ValuesCollection extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC {
		@Override
		public VALUE_ITERATOR VALUE_GENERIC iterator() { return new ValuesIterator KEY_VALUE_GENERIC_DIAMOND(SORTED_MAPS.fastIterator(ABSTRACT_SORTED_MAP.this)); }

		@Override
		public boolean contains(final VALUE_TYPE k) { return containsValue(k); }

		@Override
		public int size() { return ABSTRACT_SORTED_MAP.this.size(); }

		@Override
		public void clear() { ABSTRACT_SORTED_MAP.this.clear(); }
	}

	/** A wrapper exhibiting a map iterator as an iterator on values.
	 *
	 * <p>To provide an iterator on values, just create an instance of this
	 * class using the corresponding iterator on entries.
	 */

	protected static class ValuesIterator KEY_VALUE_GENERIC implements VALUE_ITERATOR VALUE_GENERIC {
		protected final ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> i;

		public ValuesIterator(ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> i) {
			this.i = i;
		}

		@Override
		public VALUE_GENERIC_TYPE NEXT_VALUE() { return i.next().ENTRY_GET_VALUE(); };

		@Override
		public boolean hasNext() { return i.hasNext(); }
	}
}
