//Nick Vollmer
// InfluenceWorld.cpp

#include "InfluenceWorld.h"
#include "../World/Tile.h"
#include <queue>
#include <vector>

//---------------------------------------------------------------------------------------------------------------------
// This function is called when the world is initialized. Perform any initialization you need here. The world has
// been set up at this point, so you can safely access the m_pTiles array.
// -return: true if successful, false if not.
//---------------------------------------------------------------------------------------------------------------------
bool InfluenceWorld::OnInit()
{
    SDL_Log("Initializing influence world.");

    return true;
}

//---------------------------------------------------------------------------------------------------------------------
// This function is called when a valid tile is clicked. A breadth-first search floods out from that tile, adding
// influence to each neighbor, but lessening that influence as it gets further from the original tile.
// -index: The index of the tile clicked.
//---------------------------------------------------------------------------------------------------------------------
void InfluenceWorld::OnTileSelected(int index)
{
    SDL_Log("Clicked tile %d", index);

    std::vector<TrackData*> visitedTracker; // Create a vector that will store data about the tiles we've visited
    for (int x = 0; x < kWorldSize; ++x) // Fill this with empty data for every tile in the world
    {
        TrackData* pNewTrackData = new TrackData(); // Create a new set of data
        visitedTracker.push_back(pNewTrackData); // store it in our vector
    }

    visitedTracker[index]->SetColor(TileColor::kGray); // Set the color of the first tile we're going to check in its corresponding TrackData
    visitedTracker[index]->SetDistance(0); // Set the distance of the first tile we're going to check in its corresponding TrackData

    std::queue<int> visitQueue; // Create a queue to pop the indexes of tiles on and off of
    visitQueue.push(index); // Push our first index onto the queue

    int limitTracker = 0; // Keep track of how many tiles we've looked at. This allows us to stop without looking at every tile in the world.

    while (!visitQueue.empty() && limitTracker < kTileCheckLimit) // If the queue is empty and we haven't checked more tiles than our limit
    {
        int checkIndex = visitQueue.front(); // Set checkIndex to the first item in the queue
        visitQueue.pop(); // take the first item off of the queue

        const std::vector<int> neighbors = GetNeighbors(checkIndex); // Get all the neighbors for the index we pulled off the queue

        for (const int pNeighbor : neighbors) // For every neighbor
        {
   

            if (visitedTracker[pNeighbor]->GetColor() == TileColor::kWhite) // If its corresponding data is set to white...
            {
                visitedTracker[pNeighbor]->SetColor(TileColor::kGray); // Set it to Gray
                visitedTracker[pNeighbor]->SetDistance(visitedTracker[checkIndex]->GetDistance() + 1); // Set it's distance

                visitQueue.push(pNeighbor); // Push it onto our queue to be checked
            }
        }

    visitedTracker[checkIndex]->SetColor(TileColor::kBlack); // Once we've processed this index, set its corresponding data to black
    if(visitedTracker[checkIndex]->GetDistance() == 0) // If it's distance is 0...
        m_pTiles[checkIndex]->AddInfluence(kMaxInfluence); // Add 1 to its influence
    else if (visitedTracker[checkIndex]->GetDistance() == 1) // If it's distance is 1
        m_pTiles[checkIndex]->AddInfluence(kHalfInfluence); // Add 1/2 to its influence
    else if (visitedTracker[checkIndex]->GetDistance() == 2) // If it's distance is 2
        m_pTiles[checkIndex]->AddInfluence(kFourthInfluence); // Add 1/4 to its influence
    else if (visitedTracker[checkIndex]->GetDistance() == 3) // If it's distance is 3
        m_pTiles[checkIndex]->AddInfluence(kEigthInfluence); // Add 1/8 to its influence

    ++limitTracker; // increment the limit tracker to keep track of how many tiles we've processed
    }

    for (TrackData* x : visitedTracker) //When everything is done, free all memory from the visitedTracker vector
    {
        delete x;
    }
}


//---------------------------------------------------------------------------------------------------------------------
// This function returns the four neighbors of any given index, but only if they don't loop to the other side
// of the world
//---------------------------------------------------------------------------------------------------------------------
std::vector<int> InfluenceWorld::GetNeighbors(int index)
{
    std::vector<int> neighbors; // Create a new vector to store the neighbors in

    if ((index + 1) < kWorldSize && ((index / kWorldWidth) == ((index + 1) / kWorldWidth))) //If the tile to the right is valid and doesn't loop
        neighbors.push_back((index + 1)); // Add it as a neighbor
    if ((index - 1) >= 0 && ((index / kWorldWidth) == ((index - 1) / kWorldWidth))) //If the next tile to the left is valid and doesn't loop
        neighbors.push_back((index - 1)); // Add it as a neighbor
    if ((index + kWorldWidth) < kWorldSize) //If the tile directly below is valid
        neighbors.push_back((index + kWorldWidth)); // Add it as a neighbor
    if ((index - kWorldWidth) >= 0) //If the tile directly above is valid
        neighbors.push_back((index - kWorldWidth)); // Add it as a neighbor

    return neighbors;
}

//---------------------------------------------------------------------------------------------------------------------
// This function is called when all influence is cleared (currently the ESC key). The influence on each tile will
// be cleared for you, so you don't have to handle that. You only have to clean up your own stuff.
//---------------------------------------------------------------------------------------------------------------------
void InfluenceWorld::OnClearInfluence()
{
    SDL_Log("Clearing all influence");
}

C++ Sample - Influence Map using Breadth First Search