#include <Block/SpriteBlock/PipelineBlock/Wire/Wire.hpp>
#include <Machine/IElectricMachine.hpp>
#include <Machine/Machine.hpp>
#include <WorldComponent/Wiring/ElectricWiring/ElectricWiring.hpp>
#include <MachineComponent/MultiBlockComponent/MultiBlockComponent.hpp>

Wire::Wire(std::string name, std::string displayName, const char *textureNameFormat) :
    PipelineBlock(name, displayName, textureNameFormat, 3)
{}

bool Wire::shouldConnectOnSide(LocalWorld &world, glm::ivec3 pos, Side side)
{
    pos += side.out();

    Block *block = world.getBlockAt(pos);
    if (block == nullptr)
    {
        return false;
    }

    if (block->isSuffixed("Wire"))
    {
        return true;
    }

    if (block->isSuffixed("Casing"))
    {
        uint8_t meta = *world.getBlockMeta(pos);
        MultiBlockComponent::CasingConnectorType connectorType = static_cast<MultiBlockComponent::CasingConnectorType>(meta & 0xF);
        if (
            connectorType == MultiBlockComponent::CasingConnectorType::EnergyInput ||
            connectorType == MultiBlockComponent::CasingConnectorType::EnergyOutput
        )
        {
            Side casingConnectorSide(meta >> 4);
            if (casingConnectorSide == side.opposite())
            {
                return true;
            }
        }
    }

    std::shared_ptr<IElectricMachine> electricMachine = std::dynamic_pointer_cast<IElectricMachine>(world.getMachine(pos));
    if (electricMachine == nullptr)
    {
        return false;
    }

    return electricMachine->canConnectElectricWire(side.opposite());
}

Wiring& Wire::getWiringFor(Chunk &chunk)
{
    return chunk.getNode()->getComponent<ElectricWiring>();
}