package com.googlecode.totallylazy.template; import com.googlecode.totallylazy.functions.Function1; import com.googlecode.totallylazy.functions.Function2; import com.googlecode.totallylazy.io.Uri; import com.googlecode.totallylazy.predicates.Predicate; import com.googlecode.totallylazy.predicates.Predicates; import com.googlecode.totallylazy.xml.Xml; import java.io.IOException; import java.net.URLEncoder; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static com.googlecode.totallylazy.Strings.string; import static com.googlecode.totallylazy.Unchecked.cast; import static com.googlecode.totallylazy.predicates.Predicates.always; import static com.googlecode.totallylazy.template.CompositeRenderer.compositeRenderer; public class Templates implements Renderers { private final Function2<? super String, ? super Renderers, ? extends Renderer<?>> missing; private final ConcurrentMap<String, Renderer<Object>> renderers = new ConcurrentHashMap<>(); private volatile CompositeRenderer implicits = CompositeRenderer.compositeRenderer(); private Templates(Function2<? super String, ? super Renderers, ? extends Renderer<?>> missing) { this.missing = missing; } public static Templates templates() { return templates(Renderers.Empty.Instance); } public static Templates templates(Class<?> aClass) { return templates(UrlRenderers.renderers(aClass)); } public static Templates templates(Uri uri) { return templates(UrlRenderers.renderers(uri)); } public static Templates templates(Renderers parent) { return templates((name, Renderers) -> parent.get(name)); } public static Templates templates(Function2<? super String, ? super Renderers, ? extends Renderer<?>> missing) { return new Templates(missing); } public Templates addDefault() { return add("raw", Default.Instance). add("html", Xml.escape()). add("xml", Xml.escape()). add("url", s -> URLEncoder.encode(string(s), "UTF-8")); } public <T> Templates add(Predicate<? super T> predicate, Function1<? super T, ? extends CharSequence> renderer) { return add(predicate, (Renderer<T>) (o, a) -> a.append(renderer.apply(o))); } public <T> Templates add(Predicate<? super T> predicate, Renderer<? super T> renderer) { implicits = implicits.add(predicate, renderer); return this; } public Templates add(String name, Function1<? super Object, ? extends CharSequence> renderer) { return add(name, (o, a) -> a.append(renderer.apply(o))); } public Templates add(String name, Renderer<? super Object> renderer) { renderers.put(name, renderer); return this; } @Override public Appendable render(Object instance, Appendable appendable) throws IOException { return implicits.render(instance, appendable); } @Override public Renderer<Object> get(String name) { return renderers.computeIfAbsent(name, n -> cast(missing.apply(n, this))); } public Templates extension(String value) { return new Templates((s, r) -> missing.apply(s + "." + value, r)); } }