#include "Train.h"

// Global train object.
Train train;

void initTrain(u8 startX, u8 startY)
{
    u8 i = 0;
    train.carriageCount = 0;

    // Set to 255 to indicate that the next position is currently unset (the train is not ready).
    train.nextX = 255;
    train.nextY = 255;

    for (i = 0; i < MAX_CARRIAGE_COUNT; ++i)
    {
        // Set all carriages to the map starting position initially.
        train.x[i] = startX;
        train.y[i] = startY;
    }

    train.redraw = TRUE;
}

void drawTrain()
{
    if (train.redraw)
    {
        u8 i = 0;

        for (i = 0; i < train.carriageCount; ++i)
        {
            drawCarriage(train.x[i], train.y[i]);
        }

        train.redraw = FALSE;
    }
}

void logicTrain()
{
    if (trainTimerElapsed())
    {
        // Train has not started moving.
        if (train.nextX == 255)
        {
            u8 currentX = train.x[0];
            u8 currentY = train.y[0];
            u8 direction = 0;
            u8 foundValidCell = FALSE;

            // Locate if there is a cell connected to the starting position (can be connected in any direction).
            for (direction = 0; direction < DIRECTION_COUNT; ++direction)
            {
                // Determine the next cell from the start position and the current direction.
                u8 nextCell = mapCell(currentX + directionX[direction], currentY + directionY[direction], 0, 0);

                if (isNextCellValid(nextCell, direction))
                {
                    // The first cell that is found is the one that will be used.
                    foundValidCell = TRUE;
                    break;
                }
            }

            if (foundValidCell)
            {
                train.nextX = currentX + directionX[direction];
                train.nextY = currentY + directionY[direction];
                train.carriageCount = 1;
                train.direction = direction;
            }
            else
            {
                // Could not find valid cell to start train into.
                gameRunning = FALSE;
                levelState = LEVEL_DEATH;
            }
        }
        else
        {
            u8 i = 0;
            u8 nextCell = mapCell(train.nextX, train.nextY, 0, 0);

            // Check if the next cell is valid
            if (nextCell)
            {
                // Check if the next cell is safe.
                if (isNextCellValid(nextCell, train.direction))
                {
                    // Clear the cell that the last carriage was occupying.
                    // Only need to do this once all carriages are displayed on the map.
                    if (train.carriageCount == MAX_CARRIAGE_COUNT)
                    {
                        drawCellAtPosition(train.x[MAX_CARRIAGE_COUNT - 1], train.y[MAX_CARRIAGE_COUNT - 1]);
                    }

                    // Shuffle carriage positions to update the position of the carriages after the first one.
                    for (i = train.carriageCount - 1; i != 0; --i)
                    {
                        train.x[i] = train.x[i - 1];
                        train.y[i] = train.y[i - 1];
                    }

                    // Move the first carriage to the next position.
                    train.x[0] = train.nextX;
                    train.y[0] = train.nextY;

                    // Determines the next direction of the train based on the next cell and the current direction.
                    train.direction = nextDirection(nextCell, train.direction);

                    // Calculate the position the first carriage will move the next time.
                    train.nextX = train.x[0] + directionX[train.direction];
                    train.nextY = train.y[0] + directionY[train.direction];

                    // Update carriage count if less than maximum carriage count.
                    // This will make additional carriages appear on the screen.
                    if (train.carriageCount < MAX_CARRIAGE_COUNT)
                    {
                        ++train.carriageCount;
                    }

                    // Update the player's score for each cell travelled.
                    // TODO figure out how to assign different pieces to different players.
                    players[0].score += 100;
                    hudRedraw = TRUE;

                    // Train has moved so redraw it on the screen.
                    train.redraw = TRUE;
                }
                else if (nextCell == CELL_MAP_FEATURE_FLAG + 2)
                {
                    // Reached the end successfully.
                    gameRunning = FALSE;
                    levelState = LEVEL_COMPLETE;
                }
                else
                {
                    // The next cell does not have correctly connected track.
                    gameRunning = FALSE;
                    levelState = LEVEL_DEATH;
                }
            }
            else
            {
                // The next cell is empty.
                gameRunning = FALSE;
                levelState = LEVEL_DEATH;
            }
        }

        // Start the train timer again for the next update.
        startTrainTimer();
    }
}

void drawCarriage(u8 x, u8 y)
{
    u16 targetX = x * 16 * scaleFactor;
    u16 targetY = y * 16 * scaleFactor;

    al_draw_scaled_bitmap(allegroTrainSprites[trainColour], 0, 0, TILE_WIDTH_BYTES * 2, TILE_HEIGHT, targetX, targetY, 16 * scaleFactor, 16 * scaleFactor, 0);
}

u8 isNextCellValid(u8 nextCell, u8 direction)
{
    if (direction == DIRECTION_RIGHT)
    {
        if (nextCell == TRACK_HORIZONTAL || nextCell == TRACK_CROSS || nextCell == TRACK_DOWN_LEFT || nextCell == TRACK_UP_LEFT)
        {
            return TRUE;
        }
    }
    else if (direction == DIRECTION_LEFT)
    {
        if (nextCell == TRACK_HORIZONTAL || nextCell == TRACK_CROSS || nextCell == TRACK_DOWN_RIGHT || nextCell == TRACK_UP_RIGHT)
        {
            return TRUE;
        }
    }
    else if (direction == DIRECTION_UP)
    {
        if (nextCell == TRACK_VERTICAL || nextCell == TRACK_CROSS || nextCell == TRACK_DOWN_LEFT || nextCell == TRACK_DOWN_RIGHT)
        {
            return TRUE;
        }
    }
    else
    {
        if (nextCell == TRACK_VERTICAL || nextCell == TRACK_CROSS || nextCell == TRACK_UP_LEFT || nextCell == TRACK_UP_RIGHT)
        {
            return TRUE;
        }
    }

    return FALSE;
}

u8 nextDirection(u8 nextCell, u8 direction)
{
    if (direction == DIRECTION_RIGHT)
    {
        if (nextCell == TRACK_HORIZONTAL || nextCell == TRACK_CROSS)
        {
            return direction;
        }
        else if (nextCell == TRACK_DOWN_LEFT)
        {
            return DIRECTION_DOWN;
        }
        else
        {
            return DIRECTION_UP;
        }
    }
    else if (direction == DIRECTION_LEFT)
    {
        if (nextCell == TRACK_HORIZONTAL || nextCell == TRACK_CROSS)
        {
            return direction;
        }
        else if (nextCell == TRACK_DOWN_RIGHT)
        {
            return DIRECTION_DOWN;
        }
        else
        {
            return DIRECTION_UP;
        }
    }
    else if (direction == DIRECTION_UP)
    {
        if (nextCell == TRACK_VERTICAL || nextCell == TRACK_CROSS)
        {
            return direction;
        }
        else if (nextCell == TRACK_DOWN_LEFT)
        {
            return DIRECTION_LEFT;
        }
        else
        {
            return DIRECTION_RIGHT;
        }
    }
    else
    {
        if (nextCell == TRACK_VERTICAL || nextCell == TRACK_CROSS)
        {
            return direction;
        }
        else if (nextCell == TRACK_UP_LEFT)
        {
            return DIRECTION_LEFT;
        }
        else
        {
            return DIRECTION_RIGHT;
        }
    }

    // No valid direction.
    return 255;
}

u8 cellContainsCarriage(u8 x, u8 y)
{
    u8 i = 0;

    for (i = 0; i < train.carriageCount; ++i)
    {
        if (train.x[i] == x && train.y[i] == y)
        {
            return TRUE;
        }
    }

    return FALSE;
}