#include <Machine/MCrate/MCrate.hpp>
#include <Serialize/Serialize.hpp>
#include <World/LocalWorld/LocalWorld.hpp>

MCrate::MCrate(LocalWorld &world, glm::ivec3 pos) :
    Machine(world, pos),
    stacks(60)
{}

void MCrate::serializeState(std::vector<uint8_t> &outBytes)
{
    serializeInto(outBytes, stacks, nextExtractionSlot);
}

void MCrate::deserializeState(const uint8_t *data, size_t size)
{
    deserialize(data, size, stacks, nextExtractionSlot);
}

int MCrate::getNumSlots()
{
    return (int) stacks.size();
}

ItemStack MCrate::getStackInSlot(int slot)
{
    return stacks[slot];
}

void MCrate::setStackInSlot(int slot, ItemStack stack)
{
    stacks[slot] = stack;
}

bool MCrate::isAllowedStackInSlot(int slot, ItemStack stack)
{
    return true;
}

void MCrate::onItemStackEntering(Side side, ItemStack &stack)
{
    if (stack.isEmpty())
    {
        return;
    }

    insertStack(stack);

    if (stack.isEmpty())
    {
        m_world.playSound(Sound::crateItemDrop, pos);
    }
}

ItemStack MCrate::tryExtractItem(Side side, ItemFilter &filter, uint32_t modeCode)
{
    ExtractionMode mode = (ExtractionMode) modeCode;

    size_t initialSlot = 0;
    if (mode == ExtractionMode::AlternatingSlots)
    {
        initialSlot = nextExtractionSlot;
    }

    for (size_t i = 0; i < stacks.size(); i++)
    {
        size_t slotIndex = (initialSlot + i) % stacks.size();

        ItemStack &stack = stacks[slotIndex];
        if (!stack.isEmpty() && filter.matches(stack))
        {
            if (mode == ExtractionMode::AlternatingSlots)
            {
                nextExtractionSlot = (slotIndex + 1) % stacks.size();
            }

            return stack.extractOne();
        }
    }

    return ItemStack();
}

bool MCrate::canConnectExtractor(Side side)
{
    return true;
}

void MCrate::getExtractionModes(Side side, std::vector<ExtractionModeSpec> &specs)
{
    specs.push_back({(uint32_t) ExtractionMode::FirstItem, "First item from the front"});
    specs.push_back({(uint32_t) ExtractionMode::AlternatingSlots, "From alternating slots"});
}