package org.javacs;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/** Cache maps a file + an arbitrary key to a value. When the file is modified, the mapping expires. */
class Cache<K, V> {
    private class Key {
        final Path file;
        final K key;

        Key(Path file, K key) {
            this.file = file;
            this.key = key;
        }

        @Override
        public boolean equals(Object other) {
            if (other.getClass() != Key.class) return false;
            var that = (Key) other;
            return Objects.equals(this.key, that.key) && Objects.equals(this.file, that.file);
        }

        @Override
        public int hashCode() {
            return Objects.hash(file, key);
        }
    }

    private class Value {
        final V value;
        final Instant created = Instant.now();

        Value(V value) {
            this.value = value;
        }
    }

    private final Map<Key, Value> map = new HashMap<>();

    boolean needs(Path file, K key) {
        // If key is not in map, it needs to be loaded
        if (!map.containsKey(key)) return true;

        // If key was loaded before file was last modified, it needs to be reloaded
        var value = map.get(key);
        Instant modified;
        try {
            modified = Files.getLastModifiedTime(file).toInstant();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return value.created.isBefore(modified);
    }

    void load(Path file, K key, V value) {
        // TODO limit total size of cache
        map.put(new Key(file, key), new Value(value));
    }

    V get(Path file, K key) {
        var k = new Key(file, key);
        if (!map.containsKey(k)) {
            throw new IllegalArgumentException(k + " is not in map " + map);
        }
        return map.get(k).value;
    }

    void clear() {
        map.clear();
    }
}

@@ -1125,34 +1125,32 @@
 s(Path file, K k
-ey
 ) %7B%0A        // I
@@ -1188,24 +1188,60 @@
 o be loaded%0A
+        var key = new Key(file, k);%0A
         if (
@@ -1678,19 +1678,13 @@
  K k
-ey
 , V v
-alue
 ) %7B%0A
@@ -1737,16 +1737,18 @@
     
-map.put(
+var key = 
 new 
@@ -1762,30 +1762,72 @@
 e, k
-ey), new Value(
+);%0A        var value = new Value(v);%0A        map.put(key, 
 value)
-)
 ;%0A  
@@ -1847,34 +1847,32 @@
 t(Path file, K k
-ey
 ) %7B%0A        var 
@@ -1872,16 +1872,18 @@
    var k
+ey
  = new K
@@ -1884,34 +1884,32 @@
  new Key(file, k
-ey
 );%0A        if (!
@@ -1925,16 +1925,18 @@
 insKey(k
+ey
 )) %7B%0A   
@@ -2043,16 +2043,18 @@
 ap.get(k
+ey
 ).value;

Fix needs(_)