package stream.flarebot.flarebot.util;

import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;

public class ExpiringMap<K, V> {

    private final TreeMap<Long, ConcurrentMap<K, V>> elem;
    private final long expireAfterMS;

    public ExpiringMap(long expireAfterMS) {
        this.expireAfterMS = expireAfterMS;
        elem = new TreeMap<>((o1, o2) -> {
            if (o1 < o2)
                return 1;
            else
                return -1;
        });
    }

    public void purge() {
        long issueMS = System.currentTimeMillis();
        Iterator<Map.Entry<Long, ConcurrentMap<K, V>>> e = elem.entrySet().iterator();
        while (e.hasNext()) {
            Map.Entry<Long, ConcurrentMap<K, V>> a = e.next();
            if (issueMS >= a.getKey()) {
                e.remove();
                System.out.println(e);
            }
            else
                break;
        }
    }

    public void put(K k, V v) {
        long ms = System.currentTimeMillis() + expireAfterMS;
        ConcurrentMap<K, V> c = elem.get(ms);
        if (c == null) {
            c = new ConcurrentHashMap<>();
            c.put(k, v);
            elem.put(ms, c);
        } else {
            c.put(k, v);
        }
    }

    public boolean containsKey(K k) {
        for(ConcurrentMap<K, V> map : elem.values()) {
            if(map.containsKey(k))
                return true;
        }
        return false;
    }

    public boolean containsValue(V v) {
        for(ConcurrentMap<K, V> map : elem.values()) {
            if(map.containsValue(v))
                return true;
        }
        return false;
    }

    public V get(K k) {
        for(ConcurrentMap<K, V> map : elem.values()) {
            if(map.get(k) != null)
                return map.get(k);
        }
        return null;
    }

    public long getValue(K k) {
        for(Long l : elem.keySet()){
            if(elem.get(l).get(k) != null)
                return l;
        }
        return -1;
    }

    public static void main(String[] args) {
        ExpiringMap<Integer, String> test = new ExpiringMap<>(1000);
        for (int i = 0; i < 1000000; i++) {
            test.put(i, String.valueOf(i));
        }

        //debug
        while (!test.elem.isEmpty()) {
            int size = test.elem.size();
            test.purge();
            if (size - test.elem.size() > 0) {
                System.out.println("Removed elements. New size: " + test.elem.size());
            }
        }
    }
}
@@ -489,126 +489,8 @@
 p%3C%3E(
-(o1, o2) -%3E %7B%0A            if (o1 %3C o2)%0A                return 1;%0A            else%0A                return -1;%0A        %7D
 );%0A 
@@ -2024,392 +2024,344 @@
 lic 
-static void main(String%5B%5D args) %7B%0A        ExpiringMap%3CInteger, String%3E test = new ExpiringMap%3C%3E(1000);%0A        for (int i = 0; i %3C 1000000; i++) %7B%0A            test.put(i, String.valueOf(i));%0A        %7D%0A%0A        //debug%0A        while (!test.elem.isEmpty()) %7B%0A            int size = test.elem.size();%0A            test.purge();%0A            if (size - test.elem.size() %3E 0) %7B%0A
+V computeIfAbsent(K key, Function%3C? super K, ? extends V%3E mappingFunction) %7B%0A        if (key == null %7C%7C mappingFunction == null) %7B%0A            throw new NullPointerException();%0A        %7D%0A%0A        for(ConcurrentMap%3CK, V%3E map : elem.values()) %7B%0A            if(map.get(key) != null)%0A                return map.get(key);%0A  
      
+ %7D%0A%0A
         
    S
@@ -2360,105 +2360,92 @@
     
-   System.out.println(%22Removed elements. New size: %22 + test.elem.size());%0A            %7D%0A        %7D
+V val = mappingFunction.apply(key);%0A%0A        this.put(key, val);%0A        return val;
 %0A   

Add more things for expiry map