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

package net.ranides.assira.collection.map;

import java.util.*;

/**
 * Interfejs definiujący mapę, która może przechowywać więcej niż jedną wartość
 * przypisaną do danego klucza.
 * @author ranides
 * @param <K>
 * @param <V> 
 */
public interface MultiMap<K,V> extends Map<K, Collection<V>> {
        
    /**
     * Sprawdza, czy podana wartość została conajmniej raz przypisana 
     * do conajmniej jednego klucza.
     * @param value
     * @return
     */
    boolean containsItem(V value);

    /**
     * Zwraca pierwszą wartość przypisaną do podanego klucza
     * @param key
     * @return {code null} - jeśli brak przypisania
     */
    V getFirst(K key);
    
    /**
     * Zwraca ostatnią wartość przypisaną do podanego klucza
     * @param key
     * @return {code null} - jeśli brak przypisania
     */
    V getLast(K key);
    
    /**
     * Dodaje kolejne przypisanie do podanego klucza, nie nadpisując ani nie
     * usuwając poprzednich.
     * @param key
     * @param value
     */
    void putItem(K key, V value);
    
    /**
     * Usuwa pierwszą wartość przypisaną do podanego klucza. Jeśli do klucza
     * przypisana była tylko jedna wartość, to klucz jest usuwany z mapy.
     * @param key
     * @return usunięty element lub {code null}, jeśli nie znaleziono przypisania
     */
    V removeFirst(K key);

    /**
     * Usuwa ostatnią wartość przypisaną do podanego klucza. Jeśli do klucza
     * przypisana była tylko jedna wartość, to klucz jest usuwany z mapy.
     * @param key
     * @return usunięty element lub {code null}, jeśli nie znaleziono przypisania
     */
    V removeLast(K key);

    /**
     * Usuwa podane powiązanie. Operacja usuwa tylko jeden element, więc jeśli 
     * podana wartość była przypisana do klucza wielokrotnie, to pozostałe wartości
     * nadal istnieją. Jeśli do klucza przypisana była tylko jedna wartość, 
     * to klucz jest usuwany z mapy.
     * @param key
     * @param value
     * @return true - jeśli znaleziono i usunięto przypisanie
     */
    boolean removeItem(K key, V value);

    /**
     * Dodaje wszystkie przypisania zdefiniowane w podanej mapie, nie nadpisując 
     * ani nie usuwając poprzednich.
     * @param source
     */
    void putItems(Map<? extends K, ? extends V> source);
    
    /**
     * Dodaje wszystkie przypisania zdefiniowane w podanej multimapie, nie nadpisując 
     * ani nie usuwając poprzednich.
     * @param source
     */
    void putItems(MultiMap<? extends K, ? extends V> source);

    /**
     * Zwraca listę wszystkich przypisanych kluczom wartości. Jeśli przypisania
     * wartości były wykonywane wielokrotnie (do jednego lub więcej kluczy) to
     * wartości będą się powtarzać.
     * @return
     */
    List<V> items();
    
    /**
     * Zwraca ilość wszystkich przypisań zdefiniowanych w mapie. Należy zwrócić 
     * uwagę, że metoda {@link size} zwraca ilość zdefniowanych kluczy, zaś 
     * poniższa zaś metoda zwraca ilość przypisanych wartości.
     * @return
     */
    int multiSize();

}
