package com.github.czyzby.autumn.mvc.component.ui.controller.impl;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.Array;
import com.github.czyzby.autumn.mvc.component.asset.AssetService;
import com.github.czyzby.autumn.mvc.component.ui.InterfaceService;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewController;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewInitializer;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewPauser;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewRenderer;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewResizer;
import com.github.czyzby.autumn.mvc.component.ui.controller.ViewShower;
import com.github.czyzby.autumn.mvc.component.ui.dto.ThemesAssignmentAction;
import com.github.czyzby.autumn.mvc.stereotype.View;
import com.github.czyzby.kiwi.util.common.Strings;
import com.github.czyzby.kiwi.util.gdx.asset.Disposables;
import com.github.czyzby.kiwi.util.gdx.collection.GdxArrays;
import com.github.czyzby.kiwi.util.gdx.reflection.Reflection;
import com.github.czyzby.lml.parser.action.ActionContainer;
import com.github.czyzby.lml.util.LmlUtilities;
/** Default controller wrapper for an object that isn't an implementation of
* {@link com.github.czyzby.autumn.mvc.component.ui.controller.ViewController}, but is annotated with
* {@link com.github.czyzby.autumn.mvc.stereotype.View}. Generally should not be used manually.
*
* @author MJ */
public class AnnotatedViewController extends AbstractAnnotatedController implements ViewController {
private final Array<Music> themes = GdxArrays.newArray();
private final View viewData;
private final String id;
private Stage stage;
private int currentThemeIndex;
private ViewRenderer viewRenderer;
private ViewResizer viewResizer;
private ViewPauser viewPauser;
private ViewShower viewShower;
private ViewInitializer viewInitializer;
// Lazy initiation to allow setting default renderers etc. in @Initiate methods.
private boolean isInitiated;
public AnnotatedViewController(final View viewData, final Object wrappedObject, final AssetService assetService) {
super(wrappedObject);
this.viewData = viewData;
id = Strings.isWhitespace(viewData.id()) ? wrappedObject.getClass().getSimpleName() : viewData.id();
loadThemes(assetService);
}
private void loadThemes(final AssetService assetService) {
if (viewData.themes().length > 0) {
if (viewData.loadThemesEagerly()) {
for (final String theme : viewData.themes()) {
themes.add(assetService.finishLoading(theme, Music.class));
}
} else {
for (final String theme : viewData.themes()) {
assetService.load(theme, Music.class);
}
assetService.addOnLoadAction(new ThemesAssignmentAction(viewData.themes(), this, assetService));
}
}
}
@Override
public void createView(final InterfaceService interfaceService) {
initiate();
stage = new Stage(interfaceService.getViewportProvider().provide(), interfaceService.getBatch());
injectStage(stage);
final Array<Actor> actors = interfaceService.getParser().createView(wrappedObject,
Gdx.files.getFileHandle(viewData.value(), viewData.fileType()));
LmlUtilities.appendActorsToStage(stage, actors);
if (viewInitializer != null) {
viewInitializer.initialize(stage, interfaceService.getParser().getActorsMappedByIds());
}
if (viewData.clearLmlMetaData()) {
LmlUtilities.clearLmlUserObjects(actors);
}
}
private ViewRenderer createRenderer() {
if (ViewRenderer.class.equals(viewData.renderer())) {
if (wrappedObject instanceof ViewRenderer) {
return (ViewRenderer) wrappedObject;
}
return InterfaceService.DEFAULT_VIEW_RENDERER;
} else if (wrappedObject.getClass().equals(viewData.renderer())) {
return (ViewRenderer) wrappedObject; // Safe to cast, wrapped has to implement VR.
}
return Reflection.newInstance(viewData.renderer());
}
private ViewResizer createResizer() {
if (ViewResizer.class.equals(viewData.resizer())) {
if (wrappedObject instanceof ViewResizer) {
return (ViewResizer) wrappedObject;
}
return InterfaceService.DEFAULT_VIEW_RESIZER;
} else if (wrappedObject.getClass().equals(viewData.resizer())) {
return (ViewResizer) wrappedObject; // Safe to cast, wrapped has to implement VR.
}
return Reflection.newInstance(viewData.resizer());
}
private ViewPauser createPauser() {
if (ViewPauser.class.equals(viewData.pauser())) {
if (wrappedObject instanceof ViewPauser) {
return (ViewPauser) wrappedObject;
}
return InterfaceService.DEFAULT_VIEW_PAUSER;
} else if (wrappedObject.getClass().equals(viewData.pauser())) {
return (ViewPauser) wrappedObject; // Safe to cast, wrapped has to implement VP.
}
return Reflection.newInstance(viewData.pauser());
}
private ViewShower createShower() {
if (ViewShower.class.equals(viewData.shower())) {
if (wrappedObject instanceof ViewShower) {
return (ViewShower) wrappedObject;
}
return InterfaceService.DEFAULT_VIEW_SHOWER;
} else if (wrappedObject.getClass().equals(viewData.shower())) {
return (ViewShower) wrappedObject; // Safe to cast, wrapped has to implement VS.
}
return Reflection.newInstance(viewData.shower());
}
private ViewInitializer createInitializer() {
if (ViewInitializer.class.equals(viewData.initializer())) {
if (wrappedObject instanceof ViewInitializer) {
return (ViewInitializer) wrappedObject;
}
return InterfaceService.DEFAULT_VIEW_INITIALIZER;
} else if (wrappedObject.getClass().equals(viewData.initializer())) {
return (ViewInitializer) wrappedObject; // Safe to cast, wrapped has to implement VI.
}
return Reflection.newInstance(viewData.initializer());
}
private void initiate() {
if (!isInitiated) {
isInitiated = true;
viewRenderer = createRenderer();
viewResizer = createResizer();
viewPauser = createPauser();
viewShower = createShower();
viewInitializer = createInitializer();
}
}
@Override
public boolean isCreated() {
return stage != null;
}
@Override
public void render(final float delta) {
viewRenderer.render(stage, delta);
}
@Override
public void resize(final int width, final int height) {
viewResizer.resize(stage, width, height);
}
@Override
public void pause() {
if (viewPauser != null) {
viewPauser.pause(this);
}
}
@Override
public void resume() {
if (viewPauser != null) {
viewPauser.resume(this);
}
}
@Override
public void show(final Action action) {
viewShower.show(stage, action);
}
@Override
public void hide(final Action action) {
viewShower.hide(stage, action);
}
@Override
public Stage getStage() {
return stage;
}
@Override
public String getViewId() {
return id;
}
@Override
public ActionContainer getActionContainer() {
if (wrappedObject instanceof ActionContainer) {
return (ActionContainer) wrappedObject;
}
return null;
}
@Override
public boolean isFirst() {
return viewData.first();
}
@Override
public void destroyView() {
Disposables.disposeOf(stage);
if (viewInitializer != null) {
viewInitializer.destroy(this);
}
stage = null;
clearStage();
}
@Override
public Array<Music> getThemes() {
return themes;
}
@Override
public Music getNextTheme() {
if (GdxArrays.isEmpty(themes)) {
return null;
} else if (GdxArrays.sizeOf(themes) == 1) {
return themes.first();
}
final Music nextTheme = themes.get(currentThemeIndex);
currentThemeIndex = viewData.themeOrdering().getNextIndex(themes, currentThemeIndex);
return nextTheme;
}
}