#ifndef CHUNK_ENCODER_HPP_
#define CHUNK_ENCODER_HPP_

#include <VoxelTree/VoxelTree.hpp>
#include <BlockAtlas/BlockAtlas.hpp>
#include <BlockEffect/BlockEffect.hpp>

class Chunk;
class ChunkWindow;

/**
 * @brief Class for encoding chunks into the SVO.
 */
class ChunkEncoder final
{
private:
    ChunkWindow &window;
    Chunk &chunk;
    BlockAtlas::SpriteID spriteGrid[16 * 16 * 16];
    std::vector<VoxelTree::NodeID> allocatedNodes;
    std::unordered_map<int, std::shared_ptr<AudioSource>> blockAudioSources;
    std::unordered_map<int, std::vector<std::shared_ptr<BlockEffect>>> blockEffects;
    std::vector<LightingStage::LightSource> initialLightSources;
    std::unordered_map<int, LightingStage::LightID> blockLightIds;

    Block& getBlockById(int id);
    VoxelTree::NodeID encodeNode(int level, glm::ivec3 offset);
    void updateBlockSound(int offsetX, int offsetY, int offsetZ, Sound &sound);
    void updateBlockEffectTable(int offsetX, int offsetY, int offsetZ, Block &block, uint8_t meta);
    void updateBlockLight(int offsetX, int offsetY, int offsetZ, Block &block, uint8_t meta);
    VoxelTree::NodeID detachRecur(VoxelTree::Order order, VoxelTree::NodeID nid);

public:
    ChunkEncoder(ChunkWindow &window, Chunk &chunk);

    ~ChunkEncoder();

    void generateGrid(const DenseArray &variantPalette, const DenseArray &blockGrid);
    void encode();
    void refreshBlock(glm::ivec3 pos);
    float getEncodingRelativeDeadline();
    void detach();
    void updateEffects(ChunkWindow &window);
    bool hasBlockEffects();
};

#endif