#include "Game.h"

void runGameSession(ALLEGRO_CONFIG* config)
{
    // Clear everything off the screen.
    al_clear_to_color(al_map_rgb(0, 0, 128));
    al_flip_display();

    // Reset game state values for a new game.
    resetGameSessionState(config);

    // Set the game to running for the game loop.
    gameRunning = TRUE;

    // Start the game from the first level.
    currentMap = 0;

    // Loop while level state is ready.
    while (!levelState)
    {
        u8 levelStartX;
        u8 levelStartY;

        // Initialise the map from the level array.
        initMap();

        // Make sure to reset count down between levels.
        if (al_get_config_value(config, NULL, "countdown_time") != NULL)
        {
            trainCountDown = atoi(al_get_config_value(config, NULL, "countdown_time"));
        }
        else
        {
            trainCountDown = 15;
        }

        // Initialise levelStart variables to the start of the selected level.
        levelStartX = level_start_position[currentMap][0];
        levelStartY = level_start_position[currentMap][1];

        // Setup the train start position.
        initTrain(levelStartX, levelStartY);

        // Initialise all the players in the game.
        initPlayers(playerCount);

        // Initially drawing the hud.
        hudRedraw = TRUE;

        // Run the actual game including the game loop.
        runGameAllegro();

        if (levelState == LEVEL_COMPLETE)
        {
            // Update current map to prepare to move to the next level.
            ++currentMap;

            // Increase the train speed between levels.
            --trainSpeed;

            // Check if all the levels have been completed.
            if (currentMap == LEVEL_COUNT)
            {
                // If currentMap is the last level then game complete
                levelState = LEVEL_GAME_COMPLETE;
            }
            else
            {
                // Move to the next level.
                levelState = LEVEL_READY;
                gameRunning = TRUE;
            }
        }
    }
}

void runGameAllegro()
{
    u8 logicFlag = 0;
    const u8 logicSpeed = 60;
    ALLEGRO_TIMER* timer = al_create_timer(1.0 / logicSpeed);
    ALLEGRO_EVENT allegroEvent;

    ALLEGRO_EVENT_QUEUE* gameEventQueue = al_create_event_queue();
    al_register_event_source(gameEventQueue, al_get_keyboard_event_source());
    al_register_event_source(gameEventQueue, al_get_timer_event_source(timer));
    al_register_event_source(gameEventQueue, al_get_display_event_source(al_get_current_display()));

    // Start the timer that will ensure the logic is at a consistent speed.
    al_start_timer(timer);

    // Setup timers required for the game.
    initialiseAllAllegroTimers();

    // Start the level count down timer before the train can start.
    startCountDownTimer(trainCountDown);

    while (gameRunning)
    {
        al_wait_for_event(gameEventQueue, &allegroEvent);

        // Read input from the player.
        readInput(gameEventQueue, &allegroEvent);

        // Only run logic every second time.
        if (logicFlag++)
        {
            // Run the game logic which will change what is displayed.
            gameLogic();

            // Reset flag
            logicFlag = 0;
        }

        // Draws the game on the screen.
        drawGame();

        al_flip_display();
    }

    // Displays dialog with map behind it showing the player if they have completed or lost the level.
    if (levelState == LEVEL_DEATH)
    {
        crashDialog(gameEventQueue, &allegroEvent);
    }
    else if (levelState == LEVEL_COMPLETE)
    {
        levelCompleteDialog(gameEventQueue, &allegroEvent);
    }

    // Destroy the timers once the game is done with them
    destroyAllAllegroTimers();
}

void readInput(ALLEGRO_EVENT_QUEUE* eventQueue, ALLEGRO_EVENT* allegroEvent)
{
    // Reads the game controls from the player.
    readGameControlsAllegro(allegroEvent);

    // Check that the exit key has been pressed.
    if (gameControls.controlFlags & CONTROL_EXIT_FLAG)
    {
        // If the player chooses to press yes exit the game.
        if (exitDialogAllegro(eventQueue, allegroEvent))
        {
            gameRunning = FALSE;
            levelState = LEVEL_EXIT;
        }
        else
        {
            al_clear_to_color(al_map_rgb(0, 0, 128));
            al_flip_display();

            // Ensure that the hud is immediately redrawn after the dialog is closed.
            hudRedraw = TRUE;

            // Force a map redraw to cleanup after the dialog is closed.
            mapRedraw = TRUE;
        }
    }
}

void drawGame()
{
    // Draws the map grid on the screen.
    drawMap();

    // Draw the player cursor(s) on the screen.
    drawPlayers();

    // Draw the train carriages on the screen.
    drawTrain();

    // Draw the hud at the bottom of the screen.
    drawHud();
}

void gameLogic()
{
    // Move the player cursor.
    movePlayer();

    // Run the logic for updating train positions.
    logicTrain();

    // Update the train count down and redraw the hud as it updates.
    if (countDownRemaining() != trainCountDown)
    {
        trainCountDown = countDownRemaining();
        hudRedraw = TRUE;
    }

    // Once the count down has ended start the train timer.
    if (trainCountDown == 0 && !countDownStopped())
    {
        // Finished with count down timer.
        stopCountDownTimer();

        // Starts the train timer used to slow down the train.
        startTrainTimer();
    }
}