package com.github.czyzby.lml.scene2d.ui.reflected;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.github.czyzby.kiwi.util.gdx.collection.GdxArrays;
import com.github.czyzby.kiwi.util.gdx.collection.pooled.PooledList;
import com.github.czyzby.lml.util.LmlUtilities;
import com.github.czyzby.lml.util.collection.IgnoreCaseStringMap;
/** This is a LML internal utility actor container. It extends {@link Actor} class, but not
* {@link com.badlogic.gdx.scenes.scene2d.Group Group}. While it contains multiple actors, it does not display them in
* any way, nor is it cleared when the actors are added to a {@link com.badlogic.gdx.scenes.scene2d.Group Group}.
*
* @author MJ
* @see #getActors()
* @see #getActor(String) */
public class ActorStorage extends Actor {
private final Array<Actor> actors = GdxArrays.newArray();
/** @param actor will be stored. */
public void addActor(final Actor actor) {
actors.add(actor);
}
/** @return direct reference to the array storing managed actors.
* @see #getActor(String) */
public Array<Actor> getActors() {
return actors;
}
/** @param id ID of the actor set in a LML template with the "id" attribute.
* @return actor with the selected ID, or null if: ID was null, no actor was found or the actor with this ID was not
* a direct child of storage in LML template. Use {@link #findActor(String)} to search for actors
* recursively.
* @see #getActor(String, Class)
* @see #findActor(String) */
public Actor getActor(final String id) {
if (id == null) {
return null;
}
for (final Actor actor : actors) {
if (id.equals(LmlUtilities.getActorId(actor))) {
return actor;
}
}
return null;
}
/** @param id ID of the actor set in a LML template with the "id" attribute.
* @param withType class of the actor. The actor will be automatically casted for convenience.
* @return actor with the selected ID, or null if: ID was null, no actor was found or the actor with this ID was not
* a direct child of storage in LML template. Use {@link #findActor(String, Class)} to search for actors
* recursively.
* @see #getActor(String)
* @see #findActor(String, Class)
* @param <Widget> type of the actor. */
@SuppressWarnings("unchecked")
public <Widget extends Actor> Widget getActor(final String id, final Class<Widget> withType) {
return (Widget) getActor(id);
}
/** @param id ID of the actor set in a LML template with the "id" attribute.
* @return actor with the selected ID, or null if no actor was found or the id parameter is null. Note that this
* method performs a somewhat expensive recursive search for the actor; if the actor that you want to get
* the reference to was a direct child of the storage in the LML file, you should use the
* {@link #getActor(String)} method.
* @see #getActor(String)
* @see #findActor(String, Class) */
public Actor findActor(final String id) {
if (id == null) {
return null;
}
for (final Actor actor : actors) {
if (id.equals(LmlUtilities.getActorId(actor))) {
return actor;
} else if (actor instanceof Group) {
final Actor child = LmlUtilities.getActorWithId((Group) actor, id);
if (child != null) {
return child;
}
}
}
return null;
}
/** @param id ID of the actor set in a LML template with the "id" attribute.
* @param withType class of the actor. The actor will be automatically casted for convenience.
* @return actor with the selected ID, or null if no actor was found or the id parameter is null. Note that this
* method performs a somewhat expensive recursive search for the actor; if the actor that you want to get
* the reference to was a direct child of the storage in the LML file, you should use the
* {@link #getActor(String, Class)} method.
* @see #getActor(String, Class)
* @see #findActor(String)
* @param <Widget> type of the actor. */
@SuppressWarnings("unchecked")
public <Widget extends Actor> Widget findActor(final String id, final Class<Widget> withType) {
return (Widget) findActor(id);
}
/** @param searchRecursively if true, any {@link Group} extending actors will also be searched through and any of
* their children with IDs will be added to the map. Note that recursive search might be an expensive
* operation and if you are sure that all actors with IDs (that you need) were _direct_ children of the
* storage in LML, you should run this method with "false".
* @return stored actors mapped by their IDs. Note that actors without IDs will be ignored and won't be added to the
* map. */
public ObjectMap<String, Actor> getActorsMappedByIds(final boolean searchRecursively) {
final ObjectMap<String, Actor> actorsByIds = new IgnoreCaseStringMap<Actor>();
for (final Actor actor : actors) {
final String id = LmlUtilities.getActorId(actor);
if (id != null) {
actorsByIds.put(id, actor);
}
}
if (!searchRecursively) {
return actorsByIds;
}
// Recursive ID search - need to scan all groups:
final PooledList<Group> groupsToSearch = new PooledList<Group>();
for (final Actor actor : actors) {
if (actor instanceof Group) {
groupsToSearch.add((Group) actor);
}
}
while (!groupsToSearch.isEmpty()) {
for (final Actor actor : groupsToSearch.removeFirst().getChildren()) {
final String id = LmlUtilities.getActorId(actor);
if (id != null) {
actorsByIds.put(id, actor);
}
if (actor instanceof Group) {
groupsToSearch.add((Group) actor);
}
}
}
return actorsByIds;
}
}