package com.github.czyzby.lml.parser.impl.tag;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.EventListener;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.LmlParserListener;
import com.github.czyzby.lml.parser.impl.tag.macro.util.Equation;
import com.github.czyzby.lml.parser.tag.LmlActorBuilder;
import com.github.czyzby.lml.parser.tag.LmlTag;
import com.github.czyzby.lml.scene2d.ui.reflected.ActorStorage;
import com.github.czyzby.lml.util.LmlUtilities;
/** Base for tags that attach a listener to actors. Exploits {@link ActorStorage} utility to store a list of actors
* without putting them in a {@link com.badlogic.gdx.scenes.scene2d.Group Group}. By default, when the event occurs,
* child actors of this tag will be added to the stage. Note that most of its attributes are ignored.
*
* @author MJ */
public abstract class AbstractListenerLmlTag extends AbstractActorLmlTag implements LmlParserListener {
private String condition;
private String[] ids;
private boolean keep;
public AbstractListenerLmlTag(final LmlParser parser, final LmlTag parentTag, final StringBuilder rawTagData) {
super(parser, parentTag, rawTagData);
}
@Override
protected Actor getNewInstanceOfActor(final LmlActorBuilder builder) {
return new ActorStorage();
}
/** @return stored actor, casted to {@link ActorStorage} for convenience. */
protected ActorStorage getActorStorage() {
return (ActorStorage) getActor();
}
@Override
public boolean isAttachable() {
return true;
}
@Override
protected void doOnTagClose() {
if (getParent() == null) {
getParser().throwErrorIfStrict(
"This tag should be attached to other actors. Listener tags produce mock-up actors and cannot be root tags.");
}
if (ids != null && ids.length > 0) {
getParser().doAfterParsing(this);
}
}
/** @param ids should not be null. Actors with these IDs will have the listener attached after template parsing. */
public void setIds(final String[] ids) {
this.ids = ids;
}
@Override
protected void handlePlainTextLine(final String plainTextLine) {
getActorStorage().addActor(toLabel(plainTextLine));
}
@Override
protected void handleValidChild(final LmlTag childTag) {
getActorStorage().addActor(childTag.getActor());
}
@Override
public void attachTo(final LmlTag tag) {
attachListener(tag.getActor());
}
/** @param condition LML equation snippet that will be processed each time the event occurs. If returns positive
* result, actors will be shown on the stage. Can be null (this is actually the default value) - if null,
* actors are displayed on each event. */
public void setCondition(final String condition) {
this.condition = condition;
}
/** @param keep if true and {@link #setIds(String[])} is used, this listener will be attached to every actor with
* the selected ID in every following parsed template. This setting allows to cache and reuse the same
* listener on multiple views. */
public void setKeepListener(final boolean keep) {
this.keep = keep;
}
/** @param actor should have a listener attached. The listener should call {@link #doOnEvent(Actor)} when the event
* occurs. */
protected void attachListener(final Actor actor) {
actor.addListener(getEventListener());
}
/** @return managed {@link EventListener} instance. */
protected abstract EventListener getEventListener();
/** @param actor has the listener attached. Its stage will be used to display stored actors. */
protected void doOnEvent(final Actor actor) {
if (condition != null) {
final boolean shouldDisplay = new Equation(getParser(), actor).getBooleanResult(condition);
if (!shouldDisplay) {
return;
}
}
LmlUtilities.appendActorsToStage(determineStage(actor), getActorStorage().getActors());
}
/** Invoked after template parsing. Hooks up the listener to actors registered by "attachTo" attribute.
*
* @param parser parsed the template.
* @param parsingResult parsed actors.
* @return {@link LmlParserListener#REMOVE} by default. See {@link #setKeepListener(boolean)}. */
@Override
public boolean onEvent(final LmlParser parser, final Array<Actor> parsingResult) {
final ObjectMap<String, Actor> actorsByIds = parser.getActorsMappedByIds();
for (final String id : ids) {
final Actor actor = actorsByIds.get(id);
if (actor != null) {
attachListener(actor);
} else if (!keep) {
parser.throwErrorIfStrict("Unknown ID: '" + id + "'. Cannot attach listener.");
}
}
return keep;
}
}