| 924 | } |
| 925 | } |
| 926 | |
| 927 | |
| 928 | static public class TemplateMap<T extends Box> implements fieldlinker.AsMap { |
| 929 | |
| 930 | |
| 931 | private final String namePrefix; |
| 932 | private final Box startFrom; |
| 933 | private final Class<T> clazz; |
| 934 | private Function<Box, T> autoconstructor; |
| 935 | |
| 936 | private BiFunction<TemplateMap<T>, Object, Object> calling; |
| 937 | |
| 938 | public TemplateMap(Box startFrom, String namePrefix, Class<T> clazz, Function<Box, T> autoconstructor) { |
| 939 | this.startFrom = startFrom; |
| 940 | this.namePrefix = namePrefix; |
| 941 | this.clazz = clazz; |
| 942 | this.autoconstructor = autoconstructor; |
| 943 | } |
| 944 | |
| 945 | @Override |
| 946 | public boolean asMap_isProperty(String p) { |
| 947 | return true; |
| 948 | } |
| 949 | |
| 950 | @Override |
| 951 | public Object asMap_call(Object a, Object b) { |
| 952 | if (calling == null) throw new Error(); |
| 953 | return calling.apply(this, b); |
| 954 | } |
| 955 | |
| 956 | @Override |
| 957 | public Object asMap_call(Object a) { |
| 958 | if (calling == null) throw new Error(); |
| 959 | return calling.apply(this, a); |
| 960 | } |
| 961 | |
| 962 | @Override |
| 963 | public Object asMap_get(String p) { |
| 964 | |
| 965 | Optional<Box> q = startFrom.breadthFirst(startFrom.upwards()) |
| 966 | .flatMap(x -> x.children() |
| 967 | .stream() |
| 968 | .filter(bx -> clazz.isInstance(bx) && bx.properties.getOr(Box.name, () -> "") |
| 969 | .equals(namePrefix + ":" + p))) |
| 970 | .findFirst(); |
| 971 | |
| 972 | |
| 973 | if (q.isPresent()) return q.get(); |
| 974 | |
| 975 | Box b = autoconstructor.apply(startFrom); |
| 976 | b.properties.put(Box.name, namePrefix + ":" + p); |
| 977 | if (!clazz.isInstance(b)) |
| 978 | throw new IllegalArgumentException(" autoconstructor didn't return an object of the correct class <" + b.getClass() + "> <" + clazz + ">"); |
| 979 | |
| 980 | startFrom.connect(b); |
| 981 | |
| 982 | return b; |
| 983 | } |