#ifndef __CATALOG_H__
#define __CATALOG_H__

#include <climits>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>

#include "CatalogItem.h"


// I mean this should go into some sort of utils
template<class T>
static inline void tokenize(
    T input,
    std::string delim,
    std::vector<std::string_view>& tokens)
{
    uint32_t prevOffset = 0;
    auto pos = std::string_view::npos;
    while ((pos = input.find(delim, prevOffset)) != std::string_view::npos)
    {
        tokens.emplace_back(input.data() + prevOffset, (pos - prevOffset));
        prevOffset = pos + delim.size();
    }

    // Final (or only one) parameter
    tokens.emplace_back(input.data() + prevOffset,
                        (input.size() - prevOffset));
}


class Catalog
{
public:

    static inline CatalogItem INVALID_ITEM{"INVALID", "INVALID"};

    Catalog();

    ~Catalog();

    int load(
        char* filePath,
        char* passwordBuffer,
        uint32_t passwordBufferSize,
        float* complete);

    inline bool getLoaded() const
    {
        return m_loaded;
    }

    inline std::vector<CatalogItem>::iterator begin()
    {
        return m_catalog.begin();
    }

    inline std::vector<CatalogItem>::iterator end()
    {
        return m_catalog.end();
    }

    inline CatalogItem& getItemById(int id)
    {
        for (auto& iter : m_catalog)
        {
            if (iter.getId() == id)
            {
                return iter;
            }
        }

        return INVALID_ITEM;
    }

    void setAllVisible();

    void filter(const std::string& criteria);

    static const char* errToString(int err)
    {
        switch (err)
        {
            case ERR_PWHASH_OUT_OF_MEMORY:
                return "pwhash: out of memory";

            case ERR_DECRYPT_INCOMPLETE_HEADER:
                return "decrypt: incomplete header";

            case ERR_DECRYPT_CORRUPTED_CHUNK:
                return "decrypt: corrupted chunk (check password)";

            case ERR_DECRYPT_PREMATURE_END:
                return "decrypt: premature end of file (file likely corrupted)";

            default:
                return "unknown error";
        }
    }


private:

    static inline const int ERR_PWHASH_OUT_OF_MEMORY         = INT_MIN + 19;
    static inline const int ERR_DECRYPT_INCOMPLETE_HEADER    = INT_MIN + 20;
    static inline const int ERR_DECRYPT_CORRUPTED_CHUNK      = INT_MIN + 21;
    static inline const int ERR_DECRYPT_PREMATURE_END        = INT_MIN + 22;

    void sort();

    bool m_loaded;
    std::vector<CatalogItem> m_catalog;

};


#endif // __CATALOG_H__