/*
 * @author Ranides Atterwim {@literal <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;


/**
 * Specialization of Map using integer keys.
 * Avoids unecessary boxing and unboxing operations.
 *
 * @param <V> V
 */
public interface IntMap<V> extends Map<Integer, V> {

    /**
     * non-generic version of method {@link #containsKey(Object)}
     * @param k k
     * @return bool
     */
    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 Set} 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 null if no value was present for the given key.
     */
    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();

    /**
     * non-generic version of method {@link #put(Object, Object)}
     *
     * @param key key
     * @param value value
     * @return value
     */
    V put(int key, V value);

    /**
     * non-generic version of method {@link #remove(Object)}
     *
     * @param key key
     * @return value
     */
    V remove(int key);

    /**
     * non-generic version of method {@link #remove(Object, Object)}
     *
     * @param key key
     * @param value value
     * @return bool
     */
    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 representing non-generic entry stored inside IntMap
     * @param <V>
     */
    interface IntEntry<V> extends Map.Entry<Integer, V> {

        /**
         * non-generic version of method {@link #getKey()}
         *
         * @return int
         */
        int getIntKey();

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

    }
}
