#ifndef WORLD_INDEX_HPP_
#define WORLD_INDEX_HPP_

#include <string>
#include <Serialize/Serialize.hpp>
#include <Version/Version.hpp>
#include <UniqueID/UniqueID.hpp>
#include <WorldTypeSettings/WorldTypeSettings.hpp>
#include <WorldAvatar/WorldAvatar.hpp>

#define WORLD_INDEX_MAGIC                                   "VOXVW"

/**
 * @brief Describes the world index file (windex.dat).
 */
class WorldIndex
{
private:
    UniqueID uniqueID;
    uint32_t flags;
    WorldAvatar avatar;
    std::string worldType;
    std::vector<uint8_t> worldTypeSettings;
    std::vector<std::string> blockTable;
    Version gameVersion;

public:
    /**
     * @brief The signature at the top of an index file.
     */
    struct Signature
    {
        char magic[5];
        Version gameVersion;
    };

    /**
     * @brief Returns true if cheats are enabled for this world.
     */
    bool areCheatsEnabled() const;

    /**
     * @brief Set the world type and its settings.
     * 
     * @param worldType The world type ID.
     * @param settings The settings.
     */
    void setSettings(std::string worldType, WorldTypeSettings &settings);

    /**
     * @brief Sync the block table with the block registry.
     */
    void syncBlockTable();

    /**
     * @brief Serialize this world index into the output vector.
     */
    void serialize(std::vector<uint8_t> &output) const;

    /**
     * @brief Deserialize the world index from the data.
     */
    size_t deserialize(const uint8_t *data, size_t size, std::string &errorOut, bool allowOtherVersion = false);

    /**
     * @brief Return the block table in this index.
     */
    const std::vector<std::string>& getBlockTable();

    /**
     * @brief Get the world type settings used in this index.
     */
    std::shared_ptr<WorldTypeSettings> loadWorldTypeSettings(std::string &errorOut);

    /**
     * @brief Get the unique ID of this world.
     */
    UniqueID getID();

    /**
     * @brief Generate a new unique ID for this world.
     */
    void generateNewID();

    /**
     * @brief Enable cheats in this world.
     */
    void enableCheats();

    /**
     * @brief Set the avatar for this world.
     */
    void setAvatar(WorldAvatar avatar);

    /**
     * @brief Get this world's avatar.
     */
    WorldAvatar getAvatar() const;

    /**
     * @brief Returns the human-readable label for the world type.
     */
    std::string getWorldTypeLabel() const;

    /**
     * @brief Get the game version this world index was created with.
     */
    Version getGameVersion() const;
    
    /**
     * @brief Create a new world index.
     * 
     * The returned world index will have a newly-generated unique ID, and flags set
     * depending on whether cheats are enabled.
     * 
     * @param cheats Whether cheats are enabled.
     * @param avatar The world avatar.
     * @return The new world index.
     */
    static WorldIndex create(bool cheats, WorldAvatar avatar);
};

PLAIN_SERIALIZABLE(WorldIndex::Signature);

template<>
struct SerialCodec<WorldIndex>
{
    static void encode(std::vector<uint8_t> &outBytes, const WorldIndex &index)
    {
        index.serialize(outBytes);
    }

    static size_t decode(const uint8_t *data, size_t size, WorldIndex &index)
    {
        std::string ignore;
        return index.deserialize(data, size, ignore);
    }
};

#endif