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

import java.util.Map;

import com.google.common.collect.Table;
import org.jetbrains.annotations.NotNull;

public enum MathUtils {
    ;

    public static <K> int increment(@NotNull final Map<K, Integer> map, @NotNull final K key, final int diff) {
        map.put(key, map.getOrDefault(key, 0) + diff);
        final int newValue = map.get(key);
        if (newValue == 0) {
            map.remove(key);
        }
        return newValue;
    }

    public static <K> long increment(@NotNull final Map<K, Long> map, @NotNull final K key, final long diff) {
        map.put(key, map.getOrDefault(key, 0L) + diff);
        final long newValue = map.get(key);
        if (newValue == 0) {
            map.remove(key);
        }
        return newValue;
    }

    @NotNull
    public static <K> Map<K, Integer> increment(@NotNull final Map<K, Integer> map, @NotNull final Map<K, Integer> diffs) {
        diffs.forEach((k, diff) -> increment(map, k, diff));
        return map;
    }

    @NotNull
    public static <K> Map<K, Integer> decrement(@NotNull final Map<K, Integer> map, @NotNull final Map<K, Integer> diffs) {
        diffs.forEach((k, diff) -> increment(map, k, -diff));
        return map;
    }

    @NotNull
    public static <R, C> Table<R, C, Integer> increment(@NotNull final Table<R, C, Integer> table, @NotNull final R r, @NotNull final C c, final int diff) {
        increment(table.row(r), c, diff);
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Long> increment(@NotNull final Table<R, C, Long> table, @NotNull final R r, @NotNull final C c, final long diff) {
        increment(table.row(r), c, diff);
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Integer> increment(@NotNull final Table<R, C, Integer> table, @NotNull final R r, @NotNull final Map<C, Integer> diffs) {
        increment(table.row(r), diffs);
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Long> incrementL(@NotNull final Table<R, C, Long> table, @NotNull final R r, @NotNull final Map<C, Long> diffs) {
        diffs.forEach((c, diff) -> increment(table, r, c, diff));
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Integer> decrement(@NotNull final Table<R, C, Integer> table, @NotNull final R r, @NotNull final Map<C, Integer> diffs) {
        decrement(table.row(r), diffs);
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Long> decrementL(@NotNull final Table<R, C, Long> table, @NotNull final R r, @NotNull final Map<C, Long> diffs) {
        diffs.forEach((c, diff) -> increment(table, r, c, -diff));
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Integer> increment(@NotNull final Table<R, C, Integer> table, @NotNull final Table<R, C, Integer> diffs) {
        diffs.rowMap().forEach((r, diff) -> increment(table, r, diff));
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Long> incrementL(@NotNull final Table<R, C, Long> table, @NotNull final Table<R, C, Long> diffs) {
        diffs.rowMap().forEach((r, diff) -> incrementL(table, r, diff));
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Integer> decrement(@NotNull final Table<R, C, Integer> table, @NotNull final Table<R, C, Integer> diffs) {
        diffs.rowMap().forEach((r, diff) -> decrement(table, r, diff));
        return table;
    }

    @NotNull
    public static <R, C> Table<R, C, Long> decrementL(@NotNull final Table<R, C, Long> table, @NotNull final Table<R, C, Long> diffs) {
        diffs.rowMap().forEach((r, diff) -> decrementL(table, r, diff));
        return table;
    }
}
