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

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import net.ranides.assira.collection.sets.IntSet;
import net.ranides.assira.generic.CompareUtils;


public interface IntMap<V> extends Map<Integer, V> {

    boolean containsKey(int k);

    /**
     * Returns a type-specific set view of the mappings contained in this map.
     *
     * <p>This method is necessary because there is no inheritance along type
     * parameters: it is thus impossible to strengthen {@link #entrySet()} so
     * that it returns an {@link it.unimi.dsi.fastutil.objects.ObjectSet} of
     * objects of type {@link java.util.Map.Entry} (the latter makes it possible
     * to access keys and values with type-specific methods).
     *
     * @return a type-specific set view of the mappings contained in this map.
     * @see #entrySet()
     */
    Set<IntEntry<V>> fastEntrySet();

    /**
     * Returns the value to which the given key is mapped.
     *
     * @param key the key.
     * @return the corresponding value, or the
     * {@linkplain #defaultReturnValue() default return value} if no value was
     * present for the given key.
     * @see Function#get(Object)
     */
    V get(int key);

    /**
     * Returns a hash code for this map.
     *
     * The hash code of a map is computed by summing the hash codes of its
     * entries.
     *
     * @return a hash code for this map.
     */
    @Override
    int hashCode();

    /**
     * Returns a type-specific-set view of the keys of this map.
     * @return a set view of the keys of this map
     */
    @Override
    IntSet keySet();

    V put(int key, V value);

    V remove(int key);
    
    default boolean remove(int key, Object value) {
        Predicate<Object> ev = CompareUtils.predicate(value);
        
        Iterator<IntEntry<V>> i = fastEntrySet().iterator();
        while (i.hasNext()) {
            IntEntry<V> e = i.next();
            if( key == e.getKey() && ev.test(e.getValue()) ) {
                i.remove();
                return true;
            }
        }
        return false;
    }

    interface IntEntry<V> extends Map.Entry<Integer, V> {

        int getIntKey();

        @Override
        default Integer getKey() {
            return getIntKey();
        }
        
    }
}
