#include <Block/SpriteBlock/BasicBlock/Dirt/Dirt.hpp>
#include <BlockRegistry/BlockRegistry.hpp>
#include <World/LocalWorld/LocalWorld.hpp>

void Dirt::scheduleGrassCheck(LocalWorld &world, glm::ivec3 pos)
{
    world.cancelSignals(pos);
    world.sendSignal(pos, sigGrassCheck, grassSpreadTicksMin + world.generateRandom() % grassSpreadTicksRange);
}

Dirt::Dirt(std::string name) : BasicBlock(name, "Dirt", 90.0f, "dirt")
{
    withDustSounds();
}

bool Dirt::canManuallyDig()
{
    return true;
}

void Dirt::onNeighborUpdated(LocalWorld &world, glm::ivec3 pos, Side side)
{
    scheduleGrassCheck(world, pos);
}

void Dirt::onPlaced(LocalWorld &world, Chunk &chunk, glm::ivec3 pos)
{
    scheduleGrassCheck(world, pos);
}

void Dirt::onSignal(LocalWorld &world, glm::ivec3 pos, uint32_t code)
{
    if (code == sigGrassCheck)
    {
        Block *block = world.getBlockAt(pos + glm::ivec3(0, 0, 1));
        if (block == nullptr)
        {
            // Block not loaded yet, try again soon.
            world.sendSignal(pos, sigGrassCheck, 1);
            return;
        }

        if (block->isFullyOpaque())
        {
            // Grass can't grow below fully opaque blocks.
            return;
        }

        glm::ivec3 delta(0, 0, 0);
        for (delta.x=-1; delta.x<=1; delta.x++)
        {
            for (delta.y=-1; delta.y<=1; delta.y++)
            {
                if (delta.x+delta.y != -1 && delta.x+delta.y != 1)
                {
                    continue;
                }

                block = world.getBlockAt(pos + delta);
                if (block == nullptr)
                {
                    // Block not loaded yet, try again soon.
                    world.sendSignal(pos, sigGrassCheck, 1);
                    return;
                }

                if (block->name == "main:grass")
                {
                    world.setBlockAt(pos, "main:grass");
                    return;
                }
            }
        }
    }
    else
    {
        BasicBlock::onSignal(world, pos, code);
    }
}

Sound& Dirt::getManualDiggingSound()
{
    return Sound::dirtDigging;
}