/*
 * GDXRoot.java
 *
 * This is the primary class file for running the game. In previous lab we
 * extended Game, which meant that all scenes had to be Screen objects. Because
 * of how Screen objects work, they could only communicate with this root via
 * listeners (e.g. callback functions).
 *
 * This time we have an alternate architecture; we use ApplicationAdapter. That
 * allows the scenes to be custom objects that talk directly to this root
 * object. They communicate via return values like getters. However, the
 * drawback is that this class must remember to call update and draw for the
 * active scene. For those of your who took 1110, it works a lot like the
 * subcontrollers in Assignment 7 for that class.
 *
 * Based on the original Optimization Lab by Don Holden, 2007
 *
 * @author: Walker M. White
 * @version: 2/2/2025
 */
package edu.cornell.cis3152.optimization;

import com.badlogic.gdx.*;
import edu.cornell.gdiac.assets.*;
import edu.cornell.gdiac.graphics.*;
import edu.cornell.gdiac.util.*;

/**
 * Root class for a LibGDX.
 *
 * This class is technically not the ROOT CLASS. Each platform has another class
 * above this (e.g. PC games use DesktopLauncher) which serves as the true root.
 * However, those classes are unique to each platform, while this class is the
 * same across all plaforms. In addition, this functions as the root class all
 * intents and purposes, and you would draw it as a root class in an
 * architecture specification.
 */
public class GDXRoot extends ApplicationAdapter {
    /** AssetManager to load game assets (textures, sounds, etc.) */
    AssetDirectory directory;
    /** Drawing context to display graphics (VIEW CLASS) */
    private SpriteBatch batch;
    /** Player mode for the asset loading screen (CONTROLLER CLASS) */
    private LoadingScene loading;
    /** Player mode for the the game proper (CONTROLLER CLASS) */
    private GameScene    playing;
    /** Polymorphic reference to the active player mode */
    private Scene active;
    /** How much time has passed so far in the game (in milliseconds) */
    private long timeElapsed;

    /**
     * Creates a new game from the configuration settings.
     *
     * This method configures the asset manager, but does not load any assets
     * or assign any screen.
     */
    public GDXRoot() {}

    /**
     * Called when the Application is first created.
     *
     * This is method immediately loads assets for the loading screen, and
     * prepares the asynchronous loader for all other assets.
     */
    @Override
    public void create() {
        // Start loading with the asset manager
        loading = new LoadingScene("assets.json" ,1);
        active = loading;

        // Initialize the loading screen
        batch  = new SpriteBatch();
    }

    /**
     * Disposes this application when it quits.
     *
     * This is preceded by a call to pause().
     */
    @Override
    public void dispose() {
        // Call dispose on our children
        if (loading != null) {
            loading.dispose();
            loading = null;
        }
        if (playing != null) {
            playing.dispose();
            playing = null;
        }

        batch.dispose();
        batch = null;

        // Unload all the resources
        if (directory != null) {
            directory.unloadAssets();
            directory.dispose();
            directory = null;
        }
        super.dispose();
    }

    /**
     * Updates the active scene and draws it to the screen.
     *
     * In class we will talk about breaking the game loop into two parts: the
     * update and the draw part.  In LibGDX, these are lumped together into a
     * single step: render().  We do not like this organization, so we have
     * split this up for the Scenes.  In particular, it allows us to add special
     * code in between update() and draw().
     */
    @Override
    public void render () {
        long time = System.currentTimeMillis();
        float delta = (time-timeElapsed)/1000.0f;
        timeElapsed = time;

        // Before we handled this with a listener
        // Now we handle it with a getter
        if (active.exitScene()) {
            if (loading != null) {
                directory = loading.getAssets();
                loading.dispose(); // This will NOT dispose the assets.
                loading = null;
                playing = new GameScene(directory);
                active = playing;
            } else {
                Gdx.app.exit();
            }
        }

        // Update the game state
        active.update(delta);
        active.draw(batch);
    }

    /**
     * Resizes this application to a new window size.
     *
     * This can happen at any point during a non-paused state but will never
     * happen before a call to create().
     *
     * @param width  The new width in pixels
     * @param height The new height in pixels
     */
    @Override
    public void resize(int width, int height) {
        if (loading != null) {
            loading.resize(width,height);
        }
        if (playing != null) {
            playing.resize(width, height);
        }
        super.resize(width,height);
    }


}
