InfoBar.java

package io.github.unisim.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import io.github.unisim.GameLogic;
import io.github.unisim.GlobalState;
import io.github.unisim.building.BuildingType;
import io.github.unisim.world.World;

import java.util.List;

/**
 * Create a Title bar with basic info.
 */
public class InfoBar {
    private ShapeActor bar;
    private Table infoTable = new Table();
    private Table titleTable = new Table();
    private Table buildingCountersTable = new Table();
    private Label[] buildingCounterLabels = new Label[4];
    private Skin skin = new Skin(Gdx.files.internal("ui/uiskin.json"));
    private Label satisfactionLabel = new Label("", skin);
    private Label studentCountLabel = new Label("", skin);
    private TextTooltip satisfactionLabelTooltip;
    private TextTooltip studentCountLabelTooltip;
    private Label periodLabel = new Label("", skin);
    private Label moneyLabel = new Label("", skin);
    private Label titleLabel = new Label("UniSim", skin);
    private Label timerLabel;
    private Label eventLabel;
    private TextTooltip eventLabelTooltip;
    private Texture pauseTexture = new Texture("ui/pause.png");
    private Texture playTexture = new Texture("ui/play.png");
    private Image pauseImage = new Image(pauseTexture);
    private Image playImage = new Image(playTexture);
    private final GameLogic gameLogic;
    private Cell<Label> timerLabelCell;
    private Cell<Label> satisfactionLabelCell;
    private Cell<Label> studentCountLabelCell;
    private Cell<Image> pauseButtonCell;
    private Cell<Table> buildingCountersTableCell;
    private Cell<Label> periodLabelCell;
    private Cell<Label> moneyLabelCell;
    private Cell<Label> eventLabelCell;
    private Cell[] buildingCounterCells;
    private World world;

    /**
     * Create a new infoBar and draws its' components onto the provided stage.
     *
     * @param stage - The stage on which to draw the InfoBar.
     */
    public InfoBar(Stage stage, GameLogic gameLogic, World world) {
        this.gameLogic = gameLogic;
        this.world = world;
        buildingCounterCells = new Cell[4];

        // Building counter table
        for (int i = 0; i < 4; i++) {
            buildingCounterLabels[i] = new Label("", skin);
        }
        buildingCounterCells[0] = buildingCountersTable.add(buildingCounterLabels[0]);
        buildingCounterCells[1] = buildingCountersTable.add(buildingCounterLabels[1]);
        buildingCountersTable.row();
        buildingCounterCells[2] = buildingCountersTable.add(buildingCounterLabels[2]);
        buildingCounterCells[3] = buildingCountersTable.add(buildingCounterLabels[3]);

        // Info Table
        timerLabel = new Label("", skin);
        eventLabel = new Label("", skin);
        infoTable.center().center();
        pauseButtonCell = infoTable.add(playImage).align(Align.center);
        timerLabelCell = infoTable.add(timerLabel).align(Align.center);
        periodLabelCell = infoTable.add(periodLabel).align(Align.center);
        moneyLabelCell = infoTable.add(moneyLabel).align(Align.center);
        satisfactionLabelCell = infoTable.add(satisfactionLabel).align(Align.center);
        studentCountLabelCell = infoTable.add(studentCountLabel).align(Align.center);
        eventLabelCell = infoTable.add(eventLabel).expandX().right();
        buildingCountersTableCell = infoTable.add(buildingCountersTable).expandX().align(Align.right);

        eventLabelTooltip = new TextTooltip("", skin);
        eventLabelTooltip.setInstant(true);
        eventLabel.addListener(eventLabelTooltip);

        satisfactionLabelTooltip = new TextTooltip("Satisfaction", skin);
        satisfactionLabelTooltip.setInstant(true);
        satisfactionLabel.addListener(satisfactionLabelTooltip);

        studentCountLabelTooltip = new TextTooltip("Student Count", skin);
        studentCountLabelTooltip.setInstant(true);
        studentCountLabel.addListener(studentCountLabelTooltip);

        // Pause button
        pauseImage.addListener(new ClickListener() {
            @Override
            public void clicked(com.badlogic.gdx.scenes.scene2d.InputEvent event, float x, float y) {
                gameLogic.pause();
            }
        });

        // Play button
        playImage.addListener(new ClickListener() {
            @Override
            public void clicked(com.badlogic.gdx.scenes.scene2d.InputEvent event, float x, float y) {
                gameLogic.unpause();
            }
        });

        titleTable.add(titleLabel).expandX().align(Align.center);

        bar = new ShapeActor(GlobalState.UIPrimaryColour);
        stage.addActor(bar);
        stage.addActor(infoTable);
        stage.addActor(titleTable);
    }

    /**
     * Called when the UI needs to be updated, usually on every frame.
     */
    public void update() {
        // Update timer label.
        float remainingTime = gameLogic.getRemainingTime();
        int remainingMinutes = (int) (remainingTime / 60.0f);
        int remainingSeconds = ((int) remainingTime) % 60;
        timerLabel.setText(String.format("%d:%02d", remainingMinutes, remainingSeconds));

        // Update period label.
        if (gameLogic.isSummer()) {
            periodLabel.setText(String.format("Year %d Summer", gameLogic.getYear()));
        } else {
            periodLabel.setText(String.format("Year %d Semester %d", gameLogic.getYear(), gameLogic.getSemester()));
        }

        // Update money, satisfaction, and student count labels.
        moneyLabel.setText(String.format("£%d", gameLogic.getMoney()));
        satisfactionLabel.setText(String.format("%d%%", gameLogic.getSatisfactionPercentage()));
        if (gameLogic.getStudentCount() >= 500) {
            studentCountLabel.setText("500+");
        } else {
            studentCountLabel.setText(gameLogic.getStudentCount());
        }

        buildingCounterLabels[0].setText("Recreation: "
            + Integer.toString(world.getBuildingCount(BuildingType.RECREATION)));
        buildingCounterLabels[1].setText("Learning: "
            + Integer.toString(world.getBuildingCount(BuildingType.LEARNING)));
        buildingCounterLabels[2].setText("Eating: "
            + Integer.toString(world.getBuildingCount(BuildingType.EATING)));
        buildingCounterLabels[3].setText("Sleeping: "
            + Integer.toString(world.getBuildingCount(BuildingType.SLEEPING)));
        pauseButtonCell.setActor(gameLogic.isPaused() ? playImage : pauseImage);

        final var tooltipLabel = eventLabelTooltip.getContainer().getActor();
        if (gameLogic.getEventManager().isEventActive()) {
            final var currentEvent = gameLogic.getEventManager().getCurrentEvent();
            eventLabel.setText(String.format("Event: %s", currentEvent.getName()));
            tooltipLabel.setText(currentEvent.getDescription());
            switch (currentEvent.getType()) {
                case NEGATIVE:
                    eventLabel.setColor(Color.RED);
                    break;
                case POSITIVE:
                    eventLabel.setColor(Color.GREEN);
                    break;
                default:
                    eventLabel.setColor(Color.WHITE);
                    break;
            }
        } else {
            eventLabel.setText("");
            tooltipLabel.setText("");
        }

        // Manually set width and pad tooltip containers to fit label properly.
        for (var tooltip : List.of(eventLabelTooltip, satisfactionLabelTooltip, studentCountLabelTooltip)) {
            tooltip.getContainer().pack();
            tooltip.getContainer().width(tooltip.getActor().getGlyphLayout().width).pad(5.0f);
        }
    }

    /**
     * Update the bounds of the background & table actors to fit the new size of the screen.
     *
     * @param width  - The new width of the screen in pixels.
     * @param height - The enw height of the screen in pixels.
     */
    public void resize(int width, int height) {
        bar.setBounds(0, height * 0.95f, width, height * 0.05f);
        infoTable.setBounds(0, height * 0.95f, width, height * 0.05f);
        titleTable.setBounds(0, height * 0.95f, width, height * 0.05f);

        float counterTableWidth = height * 0.27f;
        buildingCountersTableCell.width(counterTableWidth).height(height * 0.05f);
        for (int i = 0; i < 4; i++) {
            buildingCounterLabels[i].setFontScale(height * 0.0015f);
            buildingCounterCells[i].width(counterTableWidth * 0.5f).height(height * 0.025f);
        }

        timerLabel.setFontScale(height * 0.002f);
        timerLabelCell.width(height * 0.08f).height(height * 0.05f);
        timerLabelCell.padLeft(height * 0.005f);
        periodLabel.setFontScale(height * 0.002f);
        periodLabelCell.width(height * 0.24f).height(height * 0.05f);
        moneyLabel.setFontScale(height * 0.002f);
        moneyLabelCell.width(height * 0.16f).height(height * 0.05f);
        satisfactionLabel.setFontScale(height * 0.002f);
        satisfactionLabelCell.width(height * 0.15f).height(height * 0.05f);
        studentCountLabel.setFontScale(height * 0.002f);
        studentCountLabelCell.width(height * 0.04f).height(height * 0.05f);
        pauseButtonCell.width(height * 0.03f).height(height * 0.03f)
            .padLeft(height * 0.01f).padRight(height * 0.01f);

        titleLabel.setFontScale(height * 0.003f);
        eventLabel.setFontScale(height * 0.002f);
        eventLabelCell.padLeft(width * 0.15f);
    }
}