#include <Block/SpriteBlock/PipelineBlock/FluidPipe/FluidPipe.hpp>
#include <Machine/IFluidMachine.hpp>
#include <Machine/Machine.hpp>
#include <WorldComponent/Wiring/FluidWiring/FluidWiring.hpp>
#include <MachineComponent/MultiBlockComponent/MultiBlockComponent.hpp>

FluidPipe::FluidPipe(std::string name) :
    PipelineBlock(name, "Fluid pipe", "fluidPipe", 2)
{
    withMetalSounds();
}

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

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

    if (block->name == name)
    {
        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::FluidInput ||
            connectorType == MultiBlockComponent::CasingConnectorType::FluidOutput
        )
        {
            Side casingConnectorSide(meta >> 4);
            if (casingConnectorSide == side.opposite())
            {
                return true;
            }
        }
    }

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

    return fluidMachine->canConnectFluidPipe(side.opposite());
}

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