package speiger.src.collections.objects.maps.interfaces;

import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.collections.objects.maps.abstracts.AbstractObject2ObjectMap;
import speiger.src.collections.objects.collections.ObjectOrderedCollection;
import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
import speiger.src.collections.objects.sets.ObjectOrderedSet;
/**
 * A Special Map Interface giving Access to some really usefull functions
 * The Idea behind this interface is to allow access to functions that give control to the Order of elements.
 * Since Linked implementations as examples can be reordered outside of the Insertion Order.
 * This interface provides basic access to such functions while also providing some Sorted/NaivgableMap implementations that still fit into here.
 * 
 * @param <T> the keyType of elements maintained by this Collection
 * @param <V> the keyType of elements maintained by this Collection
 */
public interface Object2ObjectOrderedMap<T, V> extends Object2ObjectMap<T, V>
{
	/**
	 * A customized put method that allows you to insert into the first index.
	 * @param key the key that should be inserted
	 * @param value the value that should be inserted
	 * @return the previous present or default return value
	 * @see java.util.Map#put(Object, Object)
	 */
	public V putAndMoveToFirst(T key, V value);
	
	/**
	 * A customized put method that allows you to insert into the last index. (This may be nessesary depending on the implementation)
	 * @param key the key that should be inserted
	 * @param value the value that should be inserted
	 * @return the previous present or default return value
	 * @see java.util.Map#put(Object, Object)
	 */
	public V putAndMoveToLast(T key, V value);
	
	/**
	 * A alternative to putAndMoveToFirst.
	 * This method simply puts an entry at the first spot of the Map but only if the entry is missing.
	 * @param key the key that should be inserted
	 * @param value the value that should be inserted
	 * @return the previous present or default return value
	 * @see java.util.Map#put(Object, Object)
	 */
	public V putFirst(T key, V value);
	
	/**
	 * A alternative to putAndMoveToLast.
	 * This method simply puts an entry at the last spot of the Map but only if the entry is missing.
	 * @param key the key that should be inserted
	 * @param value the value that should be inserted
	 * @return the previous present or default return value
	 * @see java.util.Map#put(Object, Object)
	 */
	public V putLast(T key, V value);
	
	/**
	 * A specific move method to move a given key/value to the first index.
	 * @param key that should be moved to the first index
	 * @return true if the value was moved.
	 * @note returns false if the value was not present in the first place
	 */
	public boolean moveToFirst(T key);
	/**
	 * A specific move method to move a given key/value to the last index.
	 * @param key that should be moved to the first last
	 * @return true if the value was moved.
	 * @note returns false if the value was not present in the first place
	 */
	public boolean moveToLast(T key);
	
	/**
	 * A Specific get method that allows to move teh given key/value int the first index.
	 * @param key that is searched for
	 * @return the given value for the requested key or default return value
	 */
	public V getAndMoveToFirst(T key);
	/**
	 * A Specific get method that allows to move teh given key/value int the last index.
	 * @param key that is searched for
	 * @return the given value for the requested key or default return value
	 */
	public V getAndMoveToLast(T key);
	
	/**
	 * A method to get the first Key of a Map.
	 * @return the first key in the map
	 */
	public T firstKey();
	/**
	 * A method to get and remove the first Key of a Map.
	 * @return the first key in the map
	 */
	public T pollFirstKey();
	/**
	 * A method to get the last Key of a Map.
	 * @return the last key in the map
	 */
	public T lastKey();
	/**
	 * A method to get and remove the last Key of a Map.
	 * @return the last key in the map
	 */
	public T pollLastKey();
	
	/**
	 * A method to get the first Value of a Map.
	 * @return the first key in the map
	 */
	public V firstValue();
	/**
	 * A method to get the last Value of a Map.
	 * @return the last key in the map
	 */
	public V lastValue();
	
	
	public Object2ObjectMap.Entry<T, V> firstEntry();
	
	public Object2ObjectMap.Entry<T, V> lastEntry();
	
	public Object2ObjectMap.Entry<T, V> pollFirstEntry();
	
	public Object2ObjectMap.Entry<T, V> pollLastEntry();
	@Override
	public Object2ObjectOrderedMap<T, V> copy();
	@Override
	public ObjectOrderedSet<T> keySet();
	@Override
	public ObjectOrderedCollection<V> values();
	@Override
	public ObjectOrderedSet<Object2ObjectMap.Entry<T, V>> object2ObjectEntrySet();
	
	public default Object2ObjectOrderedMap<T, V> reversed() { return new AbstractObject2ObjectMap.ReversedObject2ObjectOrderedMap<>(this); }
	
	/**
	 * Creates a Wrapped SortedMap that is Synchronized
	 * @return a new SortedMap that is synchronized
	 * @see Object2ObjectMaps#synchronize
	 */
	@Override
	public default Object2ObjectOrderedMap<T, V> synchronize() { return Object2ObjectMaps.synchronize(this); }
	
	/**
	 * Creates a Wrapped SortedMap that is Synchronized
	 * @param mutex is the controller of the synchronization block
	 * @return a new SortedMap Wrapper that is synchronized
	 * @see Object2ObjectMaps#synchronize
	 */
	@Override
	public default Object2ObjectOrderedMap<T, V> synchronize(Object mutex) { return Object2ObjectMaps.synchronize(this, mutex); }
	
	/**
	 * Creates a Wrapped SortedMap that is unmodifiable
	 * @return a new SortedMap Wrapper that is unmodifiable
	 * @see Object2ObjectMaps#unmodifiable
	 */
	@Override
	public default Object2ObjectOrderedMap<T, V> unmodifiable() { return Object2ObjectMaps.unmodifiable(this); }
	
	/**
	 * Fast Ordered Entry Set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value
	 * @param <T> the keyType of elements maintained by this Collection
	 * @param <V> the keyType of elements maintained by this Collection
	 */
	interface FastOrderedSet<T, V> extends Object2ObjectMap.FastEntrySet<T, V>, ObjectOrderedSet<Object2ObjectMap.Entry<T, V>> {
		@Override
		public ObjectBidirectionalIterator<Object2ObjectMap.Entry<T, V>> fastIterator();
		/**
		 * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation
		 * @param fromElement that is going to be started from.
		 * @return a improved iterator that starts from the desired element
		 */
		public ObjectBidirectionalIterator<Object2ObjectMap.Entry<T, V>> fastIterator(T fromElement);
	}
}