package ru.yandex.qe.dispenser.domain.util;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
 * For construction of constant maps.
 * It is like Guava ImmutableMap, but guava has some limitations:
 * <ul>
 * <li>supports only limited number of arguments</li>
 * <li>ordering cannot be specified</li>
 * </ul>
 * Usage example:
 * <code><pre>
 *     Map&lt;String, String&gt; dictionary = MapBuilder.of ("class", "класс")
 *     .put("interface", "интерфейс")
 *     .put("function", "функция")
 *     .build();
 * </pre></code>
 *
 * The returned collection is immutable.
 *
 * <@link {@link #build()}/> may be called multiple times:
 * <code><pre>
 *     MapBuilder&lt;String, String&gt; builder = MapBuilder.of ("class", "класс");
 *     Map&lt;String, String&gt; first = builder.build();
  *    Map&lt;String, String&gt; second builder.put("interface", "интерфейс").build();
  *    // now first contains 1 pair, second contains 2 pairs
  * </pre></code> * @author lvovich
 */
@Deprecated
public class MapBuilder<K,V> {

    private final Map<K,V> map;
    private final Supplier<Map<K,V>> supplier;

    private MapBuilder(K key, V value) {
        this(key, value, HashMap::new);
    }

    private MapBuilder(K key, V value, Supplier<Map<K,V>> supplier) {
        this.supplier = supplier;
        this.map = supplier.get();
        map.put(key, value);
    }

    public MapBuilder<K,V> put(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * Builds an ummutable map.
     * @return
     */
    public Map<K,V> build() {
        Map<K, V> copy = supplier.get();
        copy.putAll(map);
        return Collections.unmodifiableMap(copy);
    }

    /**
     * A shortcut for <code>of(key, value, HashMap::new</code>
     * @param key first key
     * @param value first value
     * @param <K> key type
     * @param <V> value type
     * @return
     */
    public static <K,V> MapBuilder<K,V> of(K key, V value) {
        return new MapBuilder<K,V>(key, value);
    }

    /**
     * Creates new builder with one key-value pair
     * @param key first key
     * @param value first value
     * @param supplier the Map supplier, typically <code>TreeMap::new</code>, <code>LinkedHashMap::new</code> or like. If the supplied map already contains something,
     *                 the key-value pairs will be present but may they are overwritten by <@link>{@link #put(Object, Object)}</@link>
     * @param <K> key type
     * @param <V> value type
     * @return
     */
    public static <K,V> MapBuilder<K,V> of(K key, V value, Supplier<Map<K,V>> supplier) {
        return new MapBuilder<K,V>(key, value);
    }

}
