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

import net.ranides.assira.collection.IntCollection;

import java.io.Serializable;
import java.util.Map;
import java.util.Set;

/**
 * Lookup interfaces is map specialization which stores integer values.
 * It provides methods which avoid boxing and unboxing.
 *
 * Lookup allows you to define "default primitive value", which is returned if mapping does not exist.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @param <K> K
 */
public interface Lookup<K> extends Map<K, Integer>, Serializable {

    /**
     * Checks whether the given value is contained in {@link #values()}.
     * @param v v
     * @return bool
     */
    boolean containsValue(int v);

    /**
     * Configures primitive value which should be used as default for non-existing mapping.
     * This value is used for example by {@link #getInt} method.
     *
     * @param rv rv
     */
    void defaultReturnValue(int rv);

    /**
     * Returns primitive value which is used as default for non-existing mapping.
     * This method is used for example by {@link #getInt} method.
     * @return int
     */
    int defaultReturnValue();

    /**
     * Returns a type-specific set view of the mappings contained in this map.
     * It should work identical to {@code entrySet}, but we can't override methods by return values.
     *
     * @return set
     * @see #entrySet()
     */
    Set<LookupEntry<K>> fastEntrySet();

    /**
     * non-generic version of {@link #get(Object)}
     *
     * Returns corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was
     * present for the given key.
     *
     * @param key the key.
     * @return value
     */
    int getInt(Object key);

    /**
     * non-generic version of {@link #put(Object, Object)}
     *
     * @param key key
     * @param value value
     * @return previous value or {@code defaultValue}
     */
    int put(K key, int value);

    /**
     * non-generic version of {@link #remove(Object)}
     * @param key key
     * @return previous value or {@code defaultValue}
     */
    int removeInt(Object key);

    /**
     * Increments value for specified key.
     * Creates key, if it does not exist.
     * Removes key, if value after operation equals zero (more precisely: default value).
     *
     * @param key key
     * @return value after increment
     */
    int inc(K key);

    /**
     * Decrements value for specified key.
     * Creates key, if it does not exist.
     * Removes key, if value after operation equals zero (more precisely: default value).
     *
     * @param key key
     * @return value after decrement
     */
    int dec(K key);

    @Override
    IntCollection values();

    /**
     * Non-generic version of {@link java.util.Map.Entry} interface.
     * Represents all entries stored inside lookup. Allows reading and writing without boxing.
     *
     * @param <K> K
     */
    interface LookupEntry<K> extends Entry<K, Integer> {

        /**
         * non-generic version of {@link #setValue(Integer)}
         * @param value value
         * @return previous value or default
         */
        int setValue(int value);

        /**
         * non-generic version of {@link #getValue()}
         * @return int
         */
        int getIntValue();

        @Override
        default Integer setValue(Integer value) {
            return setValue(value.intValue());
        }

        @Override
        default Integer getValue() {
            return getIntValue();
        }
        
    }
}
