/*
 * @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.ArrayList;
import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.function.BinaryOperator;
import net.ranides.assira.collection.sets.IntOpenSet;
import net.ranides.assira.collection.sets.IntSet;

/**
 * Specialization of MultiMap using integer keys.
 * Avoids unecessary boxing and unboxing operations.
 *
 * @param <V> V
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public interface IntMultiMap<V> extends IntMap<V>, MultiMap<Integer, V> {

    /**
     * non-generic version of method {@link #getAll(Object)}
     *
     * @param key key
     * @return new collection
     */
    Collection<V> getAll(int key);

    /**
     * non-generic version of method {@link #get(Object, BinaryOperator)}
     *
     * @param key key
     * @param fold fold
     * @return value
     */
    default V get(int key, BinaryOperator<V> fold) {
        return getAll(key).stream().reduce(fold).orElseThrow(()->new NoSuchElementException());
    }

    /**
     * non-generic version of method {@link #containsEntry(Object, Object)}
     *
     * @param key key
     * @param value value
     * @return bool
     */
    default boolean containsEntry(int key, Object value) {
        return getAll(key).contains(value);
    }

    /**
     * non-generic version of method {@link #putAll(Integer, Iterable)}
     *
     * @param key key
     * @param values values
     */
    default void putAll(int key, Iterable<? extends V> values) {
        for(V value : values) {
            put(key, value);
        }
    }

    /**
     * non-generic version of method {@link #removeAll(Object)}
     *
     * @param key key
     * @return new collection
     */
    default Collection<V> removeAll(int key) {
        Collection<V> prev = new ArrayList<>();
        V last;
        while(null != (last=remove(key))) {
            prev.add(last);
        }
        return prev;
    }
    
    @Override
    default Collection<V> getAll(Object key) {
        return getAll(((Integer)key).intValue());
    }
    
    @Override
    default V get(Object key, BinaryOperator<V> fold) {
        return get(((Integer)key).intValue(), fold);
    }
    
    @Override
    default boolean containsEntry(Object key, Object value) {
        return containsEntry(((Integer)key).intValue(), value);
    }

    @Override
    default void putAll(Integer key, Iterable<? extends V> values) {
        putAll(key.intValue(), values);
    }
    
    @Override
    default Collection<V> removeAll(Object key) {
        return removeAll(((Integer)key).intValue());
    }
    
    @Override
    default IntSet uniqueKeySet() {
        return new IntOpenSet(keySet());
    }
    
    
}
