import "copyrightAndOthers.stg"

targetPath() ::= "org/eclipse/collections/api/map/primitive"

fileName(primitive) ::= "MutableObject<primitive.name>Map"

class(primitive) ::= <<
<body(primitive.type, primitive.name)>
>>

body(type, name) ::= <<
<copyrightAndOthers()>

package org.eclipse.collections.api.map.primitive;

import org.eclipse.collections.api.block.function.primitive.<name>Function;
import org.eclipse.collections.api.block.function.primitive.<name>Function0;
import org.eclipse.collections.api.block.function.primitive.<name>To<name>Function;
import org.eclipse.collections.api.block.function.primitive.<name>ToObjectFunction;
import org.eclipse.collections.api.block.function.primitive.Object<name>To<name>Function;
import org.eclipse.collections.api.block.predicate.primitive.<name>Predicate;
import org.eclipse.collections.api.block.procedure.primitive.<name>Procedure;
import org.eclipse.collections.api.block.predicate.primitive.Object<name>Predicate;
import org.eclipse.collections.api.collection.MutableCollection;
import org.eclipse.collections.api.collection.primitive.Mutable<name>Collection;
import org.eclipse.collections.api.iterator.Mutable<name>Iterator;
import org.eclipse.collections.api.tuple.primitive.Object<name>Pair;

/**
 * This file was automatically generated from template file mutableObjectPrimitiveMap.stg.
 *
 * @since 3.0.
 */
public interface MutableObject<name>Map\<K> extends Object<name>Map\<K>
{
    @Override
    Mutable<name>Iterator <type>Iterator();

    /**
     * Removes all entries from this map.
     */
    void clear();

    /**
     * Associates a value with the specified key. If a value is already associated
     * with the key in this map, it will be replaced with {@code value}.
     * @param key the key
     * @param value the value to associate with {@code value}
     */
    void put(K key, <type> value);

    /**
     * This method allows MutableObject<name>Map the ability to add an element in the form of {@code Object<name>Pair\<K>}.
     *
     * @see #put(Object, <type>)
     * @since 9.1.0
     */
    default void putPair(Object<name>Pair\<K> keyValuePair)
    {
        this.put(keyValuePair.getOne(), keyValuePair.getTwo());
    }

    /**
     * Puts all of the key/value mappings from the specified map into this map. If this
     * map already has a value associated with one of the keys in the map, it will be
     * replaced with the value in {@code map}.
     * @param map the map to copy into this map
     */
    void putAll(Object<name>Map\<? extends K> map);

    /**
     * Updates the values in-place.
     *
     * @param function that takes a key and its value and that returns a new value for this key
     * @since 10.0
     */
    void updateValues(Object<name>To<name>Function\<? super K> function);

    /**
     * Removes the mapping associated with the key, if one exists, from the map.
     * @param key the key to remove
     * @see #remove(Object)
     */
    void removeKey(K key);

    /**
     * Removes the mapping associated with the key, if one exists, from the map.
     * @param key the key to remove
     * @see #removeKey(K)
     */
    void remove(Object key);

    /**
     * Removes the mapping associated with the key, if one exists, from the map,
     * returning the previously associated value with the key. If no mapping
     * existed for the key, the specified default value is returned.
     * @param key the key to remove
     * @param value the default value to return if no mapping for the key exists
     * @return the value previously associated with the key, if one existed,
     * or {@code value} if not
     */
    <type> removeKeyIfAbsent(K key, <type> value);

    /**
     * Retrieves the value associated with the key if one exists; if it does not,
     * associates a value with the key.
     * a new value with they key
     * @param key the key
     * @param value the value to associate with {@code key} if no such mapping exists
     * @return the value associated with key, if one exists, or {@code value} if not
     */
    <type> getIfAbsentPut(K key, <type> value);

    /**
     * Retrieves the value associated with the key if one exists; if it does not,
     * associates a putValue with the key.
     * @param key the key
     * @param putValue the value to associate with {@code key} if no such mapping exists
     * @param defaultValue the value to return if no mapping associated with {@code key} exists
     * @return the value associated with key, if one exists, or {@code defaultValue} if not
     * @since 11.1.
     */
    default <type> getAndPut(K key, <type> putValue, <type> defaultValue)
    {
        <type> returnValue = this.getIfAbsent(key, defaultValue);
        this.put(key, putValue);
        return returnValue;
    }

    /**
     * Retrieves the value associated with the key if one exists; if it does not,
     * invokes the supplier and associates the result with the key.
     * @param key the key
     * @param function the supplier that provides the value if no mapping exists for {@code key}
     * @return the value associated with the key, if one exists, or the result of
     * invoking {@code function} if not
     */
    <type> getIfAbsentPut(K key, <name>Function0 function);

    /**
     * Retrieves the value associated with the key if one exists; if it does not,
     * associates the result of invoking the value function with the key.
     * @param key the key
     * @param function the function that provides the value if no mapping exists.
     * The {@code key} will be passed as the argument to the function.
     * @return the value associated with the key, if one exists, or the result of
     * invoking {@code function} with {@code key} if not
     */
    <type> getIfAbsentPutWithKey(K key, <name>Function\<? super K> function);

    /**
     * Retrieves the value associated with the key if one exists; if it does not,
     * invokes the value function with the parameter and associates the result with the key.
     * @param key the key
     * @param function the function that provides the value if no mapping exists.
     * The specified {@code parameter} will be passed as the argument to the function.
     * @param parameter the parameter to provide to {@code function} if no value
     * exists for {@code key}
     * @param \<P> the type of the value function's {@code parameter}
     * @return the value associated with the key, if one exists, or the result of
     * invoking {@code function} with {@code parameter} if not
     */
    \<P> <type> getIfAbsentPutWith(K key, <name>Function\<? super P> function, P parameter);

    /**
     * Updates or sets the value associated with the key by applying the function to the
     * existing value, if one exists, or to the specified initial value if one does not.
     * @param key the key
     * @param initialValueIfAbsent the initial value to supply to the function if no
     * mapping exists for the key
     * @param function the function that returns the updated value based on the current
     * value or the initial value, if no value exists
     * @return the new value associated with the key, either as a result of applying
     * {@code function} to the value already associated with the key or as a result of
     * applying it to {@code initialValueIfAbsent} and associating the result with {@code key}
     */
    <type> updateValue(K key, <type> initialValueIfAbsent, <name>To<name>Function function);
    <if(!primitive.booleanPrimitive)><(flipUniqueValues.(name))(name)><endif>

    @Override
    MutableObject<name>Map\<K> select(Object<name>Predicate\<? super K> predicate);

    @Override
    MutableObject<name>Map\<K> reject(Object<name>Predicate\<? super K> predicate);

    @Override
    Mutable<name>Collection select(<name>Predicate predicate);

    @Override
    Mutable<name>Collection reject(<name>Predicate predicate);

    /**
     * @since 9.0.
     */
    @Override
    default MutableObject<name>Map\<K> tap(<name>Procedure procedure)
    {
        this.forEach(procedure);
        return this;
    }

    @Override
    \<V> MutableCollection\<V> collect(<name>ToObjectFunction\<? extends V> function);

    /**
     * Associates a value with the specified key. If a value is already associated
     * with the key in this map, it will be replaced with {@code value}.
     * @param key the key
     * @param value the value to associate with {@code value}
     * @return this map
     * @see #put(K, <type>)
     */
    MutableObject<name>Map\<K> withKeyValue(K key, <type> value);

    /**
     * Removes the mapping associated with the key, if one exists, from this map.
     * @param key the key to remove
     * @return this map
     * @see #remove(Object)
     */
    MutableObject<name>Map\<K> withoutKey(K key);

    /**
     * Removes the mappings associated with all the keys, if they exist, from this map.
     * @param keys the keys to remove
     * @return this map
     * @see #remove(Object)
     */
    MutableObject<name>Map\<K> withoutAllKeys(Iterable\<? extends K> keys);

    default MutableObject<name>Map\<K> withAllKeyValues(Iterable\<Object<name>Pair\<K>\> keyValuePairs)
    {
        for (Object<name>Pair\<K> keyValuePair : keyValuePairs)
        {
            this.putPair(keyValuePair);
        }
        return this;
    }

    MutableObject<name>Map\<K> asUnmodifiable();

    MutableObject<name>Map\<K> asSynchronized();
    <(arithmeticMethods.(type))(type)>
}

>>

arithmeticMethods ::= [
    "byte": "allMethods",
    "short": "allMethods",
    "char": "allMethods",
    "int": "allMethods",
    "long": "allMethods",
    "float": "allMethods",
    "double": "allMethods",
    "boolean": "noMethods"
    ]

allMethods(type) ::= <<

<type> addToValue(K key, <type> toBeAdded);
>>

noMethods(type) ::= ""

flipUniqueValues ::= [
    "Byte": "flipUniqueValues",
    "Short": "flipUniqueValues",
    "Char": "flipUniqueValues",
    "Int": "flipUniqueValues",
    "Long": "flipUniqueValues",
    "Float": "flipUniqueValues",
    "Double": "flipUniqueValues",
    "Boolean": "noMethods"
    ]

flipUniqueValues(name) ::= <<

@Override
Mutable<name>ObjectMap\<K> flipUniqueValues();
>>
