#ifndef PIPELINE_BLOCK_HPP_
#define PIPELINE_BLOCK_HPP_

#include <optional>
#include <string>

#include <Block/SpriteBlock/SpriteBlock.hpp>
#include <World/LocalWorld/LocalWorld.hpp>
#include <WorldComponent/Wiring/Wiring.hpp>

/**
 * @brief Base class for pipeline blocks.
 * 
 * Pipeline blocks are ones which connect with each other to form networks, such
 * as fluids pipes, electric cables, etc.
 */
class PipelineBlock : public SpriteBlock
{
private:
    int pipeMargin;

    static std::vector<Sprite> makeSprites(const char *textureNameFormat, int pipeMargin);

protected:
    /**
     * @brief Get the relevant wiring component for the specified chunk.
     */
    virtual Wiring& getWiringFor(Chunk &chunk) = 0;

public:
    /**
     * @brief Construct a pipeline block.
     * 
     * @param name The block name.
     * @param displayName The display name of the block.
     * @param textureNameFormat The pipeline texture name format.
     * @param pipeMargin Margin for the connectors on the texture (between 0 and 1).
     */
    PipelineBlock(std::string name, std::string displayName, const char *textureNameFormat, int pipeMargin);

    /**
     * @brief Determine whether the specified side should have a connector drawn on it.
     * 
     * This is called from `PipelineBlock`'s methods when a neighbor is updated or when
     * the block is placed. It is used to then set the metadata, to make the correct
     * connectors render.
     * 
     * @param world The world.
     * @param pos The position of this block.
     * @param side Which side we are querying.
     * @return true If a connection should be rendered on this side.
     * @return false If the pipeline terminates on this side.
     */
    virtual bool shouldConnectOnSide(LocalWorld &world, glm::ivec3 pos, Side side) = 0;

    virtual bool canManuallyDig() override;
    virtual bool isFullyOpaque() override;
    virtual void onPlaced(LocalWorld &world, Chunk &chunk, glm::ivec3 pos) override;
    virtual void onNeighborUpdated(LocalWorld &world, glm::ivec3 pos, Side side) override;
    virtual void getCollisionBoxes(World &world, glm::ivec3 pos, std::vector<BoundingBox<wfixed>> &boxes) override;
    virtual void onRemoved(LocalWorld &world, Chunk &chunk, glm::ivec3 pos, uint8_t meta) override;
};

#endif