#include <Block/SpriteBlock/Pillar/Pillar.hpp>
#include <BoundingBox/BoundingBox.hpp>
#include <sstream>
#include <World/LocalWorld/LocalWorld.hpp>

std::vector<Pillar::Sprite> Pillar::makeSprites(std::string variantName)
{
    std::vector<Sprite> sprites;

    int i;
    for (i=0; i<metaNumStates; i++)
    {
        std::stringstream ss;
        ss << "pillar";

        std::vector<BoundingBox<int>> segments;
        segments.push_back(BoundingBox<int>{
            2, 2, 0, 6, 6, 8,
        });

        if ((i & metaPillarTop) == 0)
        {
            segments.push_back(BoundingBox<int>{
                0, 0, 7, 8, 8, 8
            });

            segments.push_back(BoundingBox<int>{
                1, 1, 6, 7, 7, 7
            });

            ss << "Topend";
        }

        if ((i & metaPillarBottom) == 0)
        {
            segments.push_back(BoundingBox<int>{
                0, 0, 0, 8, 8, 1
            });

            segments.push_back(BoundingBox<int>{
                1, 1, 1, 7, 7, 2
            });

            ss << "Bottomend";
        }

        sprites.push_back(
            Sprite{
                {variantName, variantName, variantName, variantName, variantName, variantName},
                segments,
                ss.str(),
            }
        );
    }

    return sprites;
}

void Pillar::updateState(LocalWorld &world, glm::ivec3 pos)
{
    uint8_t meta = *world.getBlockMeta(pos);
    uint8_t newMeta = 0;

    Block *above = world.getBlockAt(pos + Side::Top.out());
    Block *below = world.getBlockAt(pos + Side::Bottom.out());

    if (above == this)
    {
        newMeta |= metaPillarTop;
    }

    if (below == this)
    {
        newMeta |= metaPillarBottom;
    }

    if (newMeta != meta)
    {
        world.setBlockMeta(pos, newMeta);
    }
}

Pillar::Pillar(std::string name, std::string displayName, float hardness, std::string variantName) :
    SpriteBlock(name, displayName, hardness, "<invalid>", makeSprites(variantName)),
    variantName(variantName)
{
    withStoneSounds();
}

void Pillar::onNeighborUpdated(LocalWorld &world, glm::ivec3 pos, Side side)
{
    if (side != Side::Top && side != Side::Bottom)
    {
        return;
    }

    updateState(world, pos);
}

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

void Pillar::onDesignerInitializing(BlockSpriteDesigner &designer, ScriptEngine &engine)
{
    designer.useFallbackScript("pillar.lua");

    engine.push(variantName);
    engine.setGlobal("PILLAR_VARIANT_NAME");
}