#include <Block/SpriteBlock/MultiBlock/UraniumRefinery/UraniumRefinery.hpp>
#include <Controller/InventoryController/UraniumRefineryController/UraniumRefineryController.hpp>
#include <Entity/PhysicsEntity/CameraEntity/Player/Player.hpp>
#include <World/LocalWorld/LocalWorld.hpp>

UraniumRefinery::UraniumRefinery(std::string name) : MultiBlock(name, "Uranium refinery", {"off", "on"})
{
    int u, v, z;
    
    // Add the floor.
    for (u=-2; u<=2; u++)
    {
        for (v=0; v<=6; v++)
        {
            structure.add(u, v, -1, "main:leadCasing");
        }
    }

    // Add the walls.
    for (z=0; z<=1; z++)
    {
        // Create the left-right walls.
        for (v=0; v<=6; v++)
        {
            structure.add(-2, v, z, "main:leadCasing");
            structure.add(2, v, z, "main:leadCasing");
        }

        // Create the front and back walls; don't include the already-added left and right sections.
        for (u=-1; u<=1; u++)
        {
            structure.add(u, 6, z, "main:leadCasing");

            // Don't add the interface block itself.
            if (u != 0 || z != 0)
            {
                structure.add(u, 0, z, "main:leadCasing");
            }
        }
    }

    // Create the left-right steel casing walls.
    for (v=1; v<=5; v++)
    {
        structure.add(-1, v, 0, "main:steelCasing");
        structure.add(1, v, 0, "main:steelCasing");
    }

    // Create the front and back walls; don't include the already-added left and right sections.
    structure.add(0, 5, 0, "main:steelCasing");
    structure.add(0, 1, 0, "main:steelCasing");

    // Create the row of centrifuges.
    for (v=2; v<=4; v++)
    {
        structure.add(0, v, 0, "main:centrifuge");
    }

    // Create the tempered glass roof.
    for (u=-1; u<=1; u++)
    {
        for (v=1; v<=5; v++)
        {
            structure.add(u, v, 1, "main:temperedGlass");
        }
    }

    withMetalSounds();
}

void UraniumRefinery::getHarvestedStacks(LocalWorld &world, glm::ivec3 pos, std::vector<ItemStack> &stacks)
{
    MultiBlock::getHarvestedStacks(world, pos, stacks);
    
    std::shared_ptr<IInventory> inv = std::dynamic_pointer_cast<IInventory>(world.getMachine(pos));
    if (inv != nullptr)
    {
        int i;
        for (i=0; i<inv->getNumSlots(); i++)
        {
            ItemStack stack = inv->getStackInSlot(i);
            if (!stack.isEmpty())
            {
                stacks.push_back(stack);
            }
        }
    }
}

void UraniumRefinery::onInteract(LocalWorld &world, Player &player, glm::ivec3 pos, Side side, const RGBABytes &collisionKey)
{
    player.connectController<UraniumRefineryController>("main:UraniumRefineryController", world.getMachine(pos));
}

glm::vec3 UraniumRefinery::getLightColor(uint8_t meta)
{
    if (meta & metaActive)
    {
        return glm::vec3(0.1f, 1.0f, 0.1f);
    }
    else
    {
        return glm::vec3(0.0f);
    }
}

glm::ivec3 UraniumRefinery::getLightOffset(uint8_t meta)
{
    return glm::ivec3(4) - 4 * Structure::getIntoVector(meta & 3);
}

Sound& UraniumRefinery::getBackgroundSound(uint8_t meta)
{
    if (meta & metaActive)
    {
        return Sound::uraniumRefinery;
    }

    return Sound::NONE;
}

void UraniumRefinery::onRemoved(LocalWorld &world, Chunk &chunk, glm::ivec3 pos, uint8_t meta)
{
    int orientation = meta & 3;
    glm::ivec3 intoVector = structure.getIntoVector(orientation);

    for (int v = 2; v <= 4; v++)
    {
        world.setBlockMeta(pos + intoVector * v, 0);
    }
}