#include "loadingthread.h"

#include <SFML/Window.hpp>
#include <SFML/System.hpp>

#include <fstream>
#include <cstdio>

#include <SparrowSerializer/serializationmanager.h>

#include <SparrowRenderer/opengl.h>

LoadingThread* LoadingThread::singleton = nullptr;
std::thread* LoadingThread::thread = nullptr;

LoadingThread::LoadingThread() :
    m_currentTask(nullptr),
    m_running(true),
    m_taskProgress(0),
    m_nbTaskProcessed(0)
{
}

LoadingThread* LoadingThread::init()
{
    if(singleton == nullptr)
    {
        singleton = new LoadingThread();
        thread = new std::thread(LoadingThread::run);
    }
    return singleton;
}

void LoadingThread::destroy()
{
    if(singleton != nullptr)
    {
        singleton->m_running = false;
        thread->join();
        delete singleton;
        singleton = nullptr;
        thread = nullptr;
    }
}

void LoadingThread::run()
{
    sf::Context openglContext;
    singleton->processTasks();
}

void LoadingThread::processTasks()
{
    while(m_running)
    {
        if(m_resourceQueue.empty())
            sf::sleep(sf::milliseconds(500)); // wait for half a second
        else
        {
            ResourceInterface* res = m_resourceQueue.front();
            m_resourceQueue.pop_front();
            res->load(m_taskProgress);
            glFlush();
            if(m_taskProgress < 1.0)
                fprintf(stderr, "failed to process the following task : %s\n", res->m_name.c_str());
            else
                ++m_nbTaskProcessed;
        }
    }
}

const std::string& LoadingThread::getCurrentTaskName()
{
    const static std::string noTask = "No current task";
    if(m_currentTask != nullptr)
        return m_currentTask->m_name;
    else
        return noTask;
}

void LoadingThread::loadResourcePack(const std::string& name)
{
    std::fstream file;
    file.open("data/" + name + ".pack", std::ios_base::in);
    ObjectLoader loader;
    loader.loadAscii(file);
    file.close();
    const std::vector<ResourcePack*>& packVec = loader.getObjects<ResourcePack>();
    ResourcePack* pack = packVec[0];
    m_packs[name] = pack;
    for(ResourceInterface* res : pack->m_resources)
    {
        if((m_references[res->m_name] += 1) == 1)
            m_resourceQueue.push_back(res);
        else
            delete res;
    }
}

void LoadingThread::freeResourcePack(const std::string& name)
{
    ResourcePack* pack = m_packs[name];
    for(ResourceInterface* res : pack->m_resources)
    {
        if((m_references[res->m_name] -= 1) == 0)
        {
            m_references.erase(res->m_name);
            delete res;
        }
    }
    m_packs.erase(name);
    delete pack;
}
