#include "BufferSection.h"

#include <vector>

#include <QVBoxLayout>

#include "Building.h"
#include "DisplayName.h"
#include "ItemChipRow.h"
#include "SectionBox.h"

namespace
{

int findPerCycle(const std::map<std::string, int>& perCycle, const std::string& itemId)
{
    const std::map<std::string, int>::const_iterator it = perCycle.find(itemId);
    return (it != perCycle.end()) ? it->second : 0;
}

}  // namespace


BufferSection::BufferSection(const SelectionContext& context, QWidget* parent)
    : QWidget(parent)
{
    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(6);

    m_inputSection = new SectionBox(tr("Input buffers"), this);
    m_inputChips   = new ItemChipRow(context.itemIcons, m_inputSection);
    m_inputSection->getContentLayout()->addWidget(m_inputChips);

    m_outputSection = new SectionBox(tr("Output buffer"), this);
    m_outputChips   = new ItemChipRow(context.itemIcons, m_outputSection);
    m_outputSection->getContentLayout()->addWidget(m_outputChips);

    layout->addWidget(m_inputSection);
    layout->addWidget(m_outputSection);
}

void BufferSection::setBuffers(const Building& building,
                               const std::map<std::string, int>& perCycleInputs,
                               const std::map<std::string, int>& perCycleOutputs)
{
    std::vector<ItemChipRow::Entry> inputs;
    for (const std::pair<const ItemType, int>& entry : building.inputBuffer.counts)
    {
        ItemChipRow::Entry chip;
        chip.itemId    = entry.first.id;
        chip.countText = QString::number(entry.second);

        const int perCycle = findPerCycle(perCycleInputs, entry.first.id);
        if (perCycle > 0)
        {
            chip.subLine = tr("/ %1 per cycle").arg(perCycle);
        }
        inputs.push_back(chip);
    }

    // Output-side items are the buffered ones plus those still emerging onto the output
    // belts: an emerging item still belongs to the output buffer (REQ-MAT-OUTPUT-EMERGE),
    // so leaving it out would make it vanish from the panel while it animates.
    std::map<std::string, int> outputCounts;
    for (const Item& item : building.outputBuffer.items)
    {
        outputCounts[item.type.id]++;
    }
    for (const std::vector<BeltItemSlot>& lane : building.emergingItems)
    {
        for (const BeltItemSlot& slot : lane)
        {
            outputCounts[slot.item.type.id]++;
        }
    }
    // A configured building lists everything its cycle produces, so an output the player
    // is waiting for reads as 0 rather than being absent.
    for (const std::pair<const std::string, int>& entry : perCycleOutputs)
    {
        outputCounts.emplace(entry.first, 0);
    }

    std::vector<ItemChipRow::Entry> outputs;
    for (const std::pair<const std::string, int>& entry : outputCounts)
    {
        ItemChipRow::Entry chip;
        chip.itemId = entry.first;
        // Counted against the buffer's capacity, which is what production stops at
        // (REQ-MAT-OUTPUT-BUFFER).
        chip.countText = building.outputBuffer.capacity > 0
            ? tr("%1 / %2").arg(entry.second).arg(building.outputBuffer.capacity)
            : QString::number(entry.second);
        chip.subLine = QString::fromStdString(toDisplayName(entry.first));
        outputs.push_back(chip);
    }

    m_inputChips->setEntries(inputs);
    m_outputChips->setEntries(outputs);
    m_inputSection->setVisible(!inputs.empty());
    m_outputSection->setVisible(!outputs.empty());
    setVisible(!inputs.empty() || !outputs.empty());
}
