/*
 * Copyright 2016-2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.gov.gchq.gaffer.types;

import uk.gov.gchq.koryphe.serialisation.json.JsonSimpleClassName;

import java.util.HashMap;
import java.util.Map;

/**
 * {@code FreqMap} extends {@link HashMap} with String keys and Long values, adding an upsert operation.
 */
@JsonSimpleClassName
public class FreqMap extends HashMap<String, Long> {
    private static final long serialVersionUID = -851105369975081220L;

    public FreqMap(final Map<? extends String, ? extends Long> m) {
        super(m);
    }

    public FreqMap() {
    }

    public FreqMap(final int initialCapacity) {
        super(initialCapacity);
    }

    public FreqMap(final int initialCapacity, final float loadFactor) {
        super(initialCapacity, loadFactor);
    }

    /**
     * Adds a new key and value to the map if the key is not already there.
     * If the key is already there, the value supplied is added to the existing value for the key and the result is inserted into the map.
     *
     * @param key   The key in the map to increment or insert.
     * @param value The value to increment by or initialise to.
     */
    public void upsert(final String key, final Long value) {
        final Long currentValue = get(key);
        if (null == currentValue) {
            put(key, value);
        } else {
            put(key, currentValue + value);
        }
    }

    /**
     * Increments the value of an existing key by 1.
     * If the key doesn't exist, initialises the value to 1.
     *
     * @param key The key to increment or insert.
     */
    public void upsert(final String key) {
        upsert(key, 1L);
    }
}

/*
 * Copyright 2016-2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.gov.gchq.gaffer.types;

import jdk.nashorn.internal.runtime.regexp.joni.Regex;
import uk.gov.gchq.koryphe.serialisation.json.JsonSimpleClassName;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * {@code FreqMap} extends {@link HashMap} with String keys and Long values, adding an upsert operation.
 */
@JsonSimpleClassName
public class FreqMap extends HashMap<String, Long> {
    private static final long serialVersionUID = -851105369975081220L;

    public FreqMap(final Map<? extends String, ? extends Long> m) {
        super(m);
    }

    public FreqMap() {
    }

    public FreqMap(final int initialCapacity) {
        super(initialCapacity);
    }

    public FreqMap(final int initialCapacity, final float loadFactor) {
        super(initialCapacity, loadFactor);
    }

    /**
     * Adds a new key and value to the map if the key is not already there.
     * If the key is already there, the value supplied is added to the existing value for the key and the result is inserted into the map.
     *
     * @param key   The key in the map to increment or insert.
     * @param value The value to increment by or initialise to.
     */
    public void upsert(final String key, final Long value) {
        final Long currentValue = get(key);
        if (null == currentValue) {
            put(key, value);
        } else {
            put(key, currentValue + value);
        }
    }

    /**
     * Increments the value of an existing key by 1.
     * If the key doesn't exist, initialises the value to 1.
     *
     * @param key The key to increment or insert.
     */
    public void upsert(final String key) {
        upsert(key, 1L);
    }

    /**
     * Creates a filtered copy of the map using a supplied regex pattern.
     *
     * @param regexPattern  A valid regex pattern as a string.
     * @return  A new frequency map with only the filtered entries present.
     */
    public FreqMap filterRegex(final String regexPattern) {
        return filterPredicate((s, l) -> s.matches(regexPattern));
    }

    /**
     * Creates a filtered copy of the map using a supplied predicate.
     *
     * @param predicate  A valid predicate that can use one or both of the key-value pairings.
     * @return  A new frequency map with only the filtered entries present.
     */
    public FreqMap filterPredicate(BiPredicate<String, Long> predicate) {
        FreqMap f = new FreqMap();

        this.entrySet().stream().filter(e -> predicate.test(e.getKey(), e.getValue()))
                .forEach(e -> f.upsert(e.getKey(), e.getValue()));

        return f;
    }
}

add filtering methods