package com.rschmitt.github.crystalmethod;

import com.github.rschmitt.crystalmethod.CrystalMethod;
import com.github.rschmitt.crystalmethod.Multimethod;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;

public class StaticTest {
    private static final ConcurrentMap<Class, Multimethod> globalMultimethods = new ConcurrentHashMap<>();

    public static <T extends Multimethod<D, R, T1>, D, R, T1> void defMulti(
            Function<T1, D> dispatchFn,
            Class<T> type
    ) {
        Multimethod multimethod = CrystalMethod.buildMultimethod(dispatchFn, new HashMap(), type);
        globalMultimethods.putIfAbsent(type, multimethod);
    }

    public static <T extends Multimethod<D, R, T1>, D, R, T1> void addMethod(
            R dispatchVal,
            Function<T1, R> method,
            Class<T> type
    ) {
        Multimethod multimethod = globalMultimethods.get(type);
        // lol race conditions
        // lol the old dict is in a closure somewhere. use a WeakMap of instances i guess?
    }

    public static <T extends Multimethod<D, R, T1>, D, R, T1> R invoke(T type, T1 arg) {
        return (R) globalMultimethods.get(type).invoke(arg);
    }
}

@@ -142,32 +142,69 @@
 od.Multimethod;%0D
+%0Aimport org.testng.annotations.Test;%0D
 %0A%0D%0Aimport java.u
@@ -209,32 +209,55 @@
 .util.HashMap;%0D%0A
+import java.util.Map;%0D%0A
 import java.util
@@ -371,16 +371,65 @@
 ion;%0D%0A%0D%0A
+import static org.testng.Assert.assertEquals;%0D%0A%0D%0A
 public c
@@ -972,17 +972,17 @@
         
-R
+D
  dispatc
@@ -1061,32 +1061,38 @@
    ) %7B%0D%0A        
+global
 Multimethod mult
@@ -1090,176 +1090,344 @@
 thod
- multimethod = globalMultimethods.get(type);%0D%0A        // lol race conditions%0D%0A        // lol the old dict is in a closure somewhere. use a WeakMap of instances i guess?
+s.compute(type, (t, m) -%3E %7B%0D%0A            Map%3CD, Function%3CT1, R%3E%3E oldMap = m.getDispatchMap();%0D%0A            Map%3CD, Function%3CT1, R%3E%3E newMap = new HashMap%3C%3E();%0D%0A            newMap.putAll(oldMap);%0D%0A            newMap.put(dispatchVal, method);%0D%0A            return CrystalMethod.buildMultimethod(m.getDispatchFn(), newMap, type);%0D%0A        %7D);
 %0D%0A  
@@ -1504,17 +1504,24 @@
  invoke(
-T
+Class%3CT%3E
  type, T
@@ -1598,12 +1598,855 @@
 %0D%0A    %7D%0D
+%0A%0D%0A    @Test%0D%0A    public void test() %7B%0D%0A        defMulti(this::dispatch, GlobalMethod.class);%0D%0A%0D%0A        addMethod(%222%22, this::m2, GlobalMethod.class);%0D%0A        addMethod(%223%22, this::m1, GlobalMethod.class);%0D%0A%0D%0A        assertEquals(invoke(GlobalMethod.class, 3.1).intValue(), 1);%0D%0A        assertEquals(invoke(GlobalMethod.class, 3.2).intValue(), 1);%0D%0A        assertEquals(invoke(GlobalMethod.class, 2.7).intValue(), 2);%0D%0A%0D%0A        addMethod(%224%22, this::m1, GlobalMethod.class);%0D%0A%0D%0A        assertEquals(invoke(GlobalMethod.class, 4.9).intValue(), 1);%0D%0A    %7D%0D%0A%0D%0A    private String dispatch(double d) %7B%0D%0A        return String.valueOf((int) d);%0D%0A    %7D%0D%0A%0D%0A    private int m1(double d) %7B%0D%0A        return 1;%0D%0A    %7D%0D%0A%0D%0A    private int m2(double d) %7B%0D%0A        return 2;%0D%0A    %7D%0D%0A%0D%0A    interface GlobalMethod extends Multimethod%3CString, Integer, Double%3E %7B%7D%0D
 %0A%7D%0D%0A

Add StaticTest prototype