package xapi.ui.impl;
import xapi.annotation.inject.SingletonDefault;
import xapi.collect.api.ClassTo;
import xapi.event.api.EventHandler;
import xapi.event.api.EventManager;
import xapi.event.api.IsEventType;
import xapi.event.impl.EventTypes;
import xapi.except.NotImplemented;
import xapi.except.NotYetImplemented;
import xapi.fu.In1Out1;
import xapi.fu.Out1;
import xapi.inject.X_Inject;
import xapi.ui.api.Ui;
import xapi.ui.api.UiBuilder;
import xapi.ui.api.UiElement;
import xapi.ui.api.event.UiEventManager;
import xapi.ui.api.UiWithAttributes;
import xapi.ui.api.UiWithProperties;
import xapi.ui.service.UiService;
import xapi.util.X_String;
import static xapi.collect.X_Collect.newClassMap;
import java.util.WeakHashMap;
/**
* @author James X. Nelson (james@wetheinter.net)
* Created on 4/19/16.
*/
@SingletonDefault(implFor = UiService.class)
@SuppressWarnings("unchecked")
public class UiServiceImpl <Node, E extends UiElement<Node, ? extends Node, E>>
implements UiService <Node, E> {
private ClassTo<Out1<UiBuilder>> builderFactories;
private ClassTo<In1Out1<String, Object>> deserializers;
private ClassTo<In1Out1<Object, String>> serializers;
private final UiEventManager<Node, E> uiEvents;
private final WeakHashMap<Node, E> knownNodes;
public UiServiceImpl() {
builderFactories = newClassMap(Out1.class);
deserializers = newClassMap(In1Out1.class);
serializers = newClassMap(In1Out1.class);
uiEvents = createUiEventManager();
knownNodes = new WeakHashMap<>();
}
@Override
public String debugDump() {
StringBuilder b = new StringBuilder();
b .append("KnownNode: ").append(knownNodes.toString().replace(',', '\n'))
.append("\nDeserializers: ").append(deserializers)
.append("\nSerializers: ").append(serializers)
.append("\nBuilders: ").append(builderFactories);
return b.toString();
}
protected UiEventManager<Node,E> createUiEventManager() {
return new UiEventManager<>(this);
}
@Override
public UiEventManager<Node, E> uiEvents() {
return uiEvents;
}
@Override
public <Generic extends E> UiBuilder<E> newBuilder(Class<Generic> cls) {
final Out1<UiBuilder> factory = builderFactories.getOrCompute(cls,
key -> () -> {
UiBuilder<E> builder;
try {
builder = X_Inject.instance(UiBuilder.class);
} catch (Throwable ignored) {
builder = new UiBuilder<E>() {
@Override
protected E instantiate() {
return X_Inject.instance(cls);
}
};
}
return builder;
});
final UiBuilder<E> builder = factory.out1();
Ui ui = cls.getAnnotation(Ui.class);
if (ui != null) {
if (!ui.type().isEmpty()) {
builder.setType(ui.type());
}
if (X_String.isNotEmpty(ui.value())) {
builder.setSource(ui.value());
}
}
return builder;
}
@Override
public ClassTo<In1Out1<String, Object>> getDeserializers() {
return deserializers;
}
@Override
public ClassTo<In1Out1<Object, String>> getSerializers() {
return serializers;
}
@Override
public UiWithAttributes<Node, E> newAttributes(E e) {
final UiWithAttributes<Node, E> ui = new UiWithAttributes<>();
ui.initialize(e, this);
return ui;
}
@Override
public UiWithProperties<Node, E> newProperties(E e) {
UiWithProperties ui = new UiWithProperties<>();
ui.initialize(e, this);
return ui;
}
@Override
public Object getHost(Object from) {
throw new NotYetImplemented(getClass() + " needs to override .getHost()");
}
@Override
public EventManager newEventManager() {
return new EventManager();
}
protected Node getParent(Node node) {
throw new NotImplemented(getClass() + " must implement .getParent()");
}
@Override
public E findContainer(Node nativeNode) {
E container = knownNodes.get(nativeNode);
while (container == null) {
nativeNode = getParent(nativeNode);
container = knownNodes.get(nativeNode);
}
return container;
}
@Override
public IsEventType convertType(String nativeType) {
return EventTypes.convertType(nativeType);
}
@Override
public E bindNode(Node node, E container) {
knownNodes.put(node, container);
return container;
}
@Override
public void bindEvent(IsEventType type, E ui, Node node, EventHandler handler, boolean useCapture) {
throw new NotImplemented(getClass() + " must implement .bindEvent");
}
protected <Payload, NativeEvent> Payload toPayload(IsEventType type, E ui, Node element, NativeEvent e) {
return null;
}
}