package com.github.czyzby.autumn.mvc.component.ui.processor;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.badlogic.gdx.utils.reflect.Field;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import com.github.czyzby.autumn.annotation.OnMessage;
import com.github.czyzby.autumn.context.Context;
import com.github.czyzby.autumn.context.ContextDestroyer;
import com.github.czyzby.autumn.context.ContextInitializer;
import com.github.czyzby.autumn.context.error.ContextInitiationException;
import com.github.czyzby.autumn.mvc.component.ui.InterfaceService;
import com.github.czyzby.autumn.mvc.config.AutumnMessage;
import com.github.czyzby.autumn.mvc.stereotype.SkinAsset;
import com.github.czyzby.autumn.processor.AbstractAnnotationProcessor;
import com.github.czyzby.kiwi.util.gdx.collection.lazy.LazyObjectMap;
import com.github.czyzby.kiwi.util.gdx.reflection.Reflection;
import com.github.czyzby.kiwi.util.tuple.immutable.Pair;
/** Injects assets from application's {@link com.badlogic.gdx.scenes.scene2d.ui.Skin} (when it is fully loaded) into
* fields annotated with {@link com.github.czyzby.autumn.mvc.stereotype.SkinAsset}.
*
* @author MJ */
public class SkinAssetAnnotationProcessor extends AbstractAnnotationProcessor<SkinAsset> {
// <ID of object, ID of skin>, <field, fieldOwner>
private final ObjectMap<Pair<String, String>, Array<Pair<Field, Object>>> fieldsToInject = LazyObjectMap
.newMapOfArrays();
@Override
public Class<SkinAsset> getSupportedAnnotationType() {
return SkinAsset.class;
}
@Override
public boolean isSupportingFields() {
return true;
}
@Override
public void processField(final Field field, final SkinAsset annotation, final Object component,
final Context context, final ContextInitializer initializer, final ContextDestroyer contextDestroyer) {
fieldsToInject.get(Pair.of(annotation.value(), annotation.skin())).add(Pair.of(field, component));
}
/** Invoked when all skins are loaded. Injects skin assets.
*
* @param interfaceService used to retrieve skins.
* @return {@link OnMessage#REMOVE}. */
@SuppressWarnings("unchecked")
@OnMessage(AutumnMessage.SKINS_LOADED)
public boolean injectFields(final InterfaceService interfaceService) {
for (final Entry<Pair<String, String>, Array<Pair<Field, Object>>> entry : fieldsToInject) {
final Skin skin = interfaceService.getParser().getData().getSkin(entry.key.getSecond());
final String assetId = entry.key.getFirst();
if (skin == null) {
throw new ContextInitiationException(
"Unable to inject asset: " + assetId + ". Unknown skin ID: " + entry.key.getSecond());
}
for (final Pair<Field, Object> injection : entry.value) {
try {
Reflection.setFieldValue(injection.getFirst(), injection.getSecond(),
skin.get(assetId, injection.getFirst().getType()));
} catch (final ReflectionException exception) {
throw new GdxRuntimeException("Unable to inject skin asset: " + assetId + " from skin: " + skin
+ " to field: " + injection.getFirst() + " of component: " + injection.getSecond(),
exception);
}
}
}
fieldsToInject.clear();
return OnMessage.REMOVE;
}
}