#ifndef CHUNK_MONITOR_COMPONENT_HPP_
#define CHUNK_MONITOR_COMPONENT_HPP_

#include <ChunkHandle/ChunkHandle.hpp>
#include <MachineComponent/MachineComponent.hpp>
#include <Utilities/Extern.hpp>
#include <functional>

/**
 * @brief A machine component which allows a machine to be notified and control specific chunks.
 */
class ChunkMonitorComponent : public MachineComponent
{
public:
    typedef std::function<bool(glm::ivec3)> CanBreakCallback;
    typedef std::function<void(glm::ivec3, Block&, uint8_t, Block&, uint8_t)> BlockChangedCallback;

private:
    std::vector<ChunkHandle> monitoredChunks;
    std::vector<CanBreakCallback> canBreakRules;
    std::vector<BlockChangedCallback> blockChangedCallbacks;

public:
    static std::string tagName;

    ChunkMonitorComponent(Machine &machine);

    /**
     * @brief Returns true if the specified chunk is being monitored by this component.
     */
    bool isMonitoring(Chunk &chunk);

    /**
     * @brief Begin monitoring the following chunk.
     * 
     * Does nothing if the chunk is already monitored.
     */
    void monitor(ChunkHandle chunk);

    /**
     * @brief Add a callback which will be invoked to determine if the specified block can be broken.
     */
    void addCanBreakRule(CanBreakCallback callback);

    /**
     * @brief Returns true if this monitor has no objections to breaking the specified block.
     */
    bool canBreak(glm::ivec3 pos);

    /**
     * @brief Add a callback which will be invoked when a block is changed on a monitored chunk.
     */
    void addBlockChangedCallback(BlockChangedCallback callback);

    /**
     * @brief Report to this chunk monitor that a block has changed on a monitored chunk.
     */
    void onBlockChanged(glm::ivec3 pos, Block &oldBlock, uint8_t oldMeta, Block &newBlock, uint8_t newMeta);

    virtual void serializeState(std::vector<uint8_t> &outBytes) override;
    virtual void deserializeState(const uint8_t *bytes, size_t size) override;
    virtual bool isReady() override;
    virtual void onRemoving() override;
};

#endif