#include "resourcepack.h"

#include "loader.h"
#include "resourcemanager.h"

#include <fstream>

#include <SparrowRenderer/texture.h>
#include <SparrowRenderer/image.h>
#include <SparrowRenderer/pbrmaterial.h>

#include <SparrowSerializer/serializationmanager.h>

#include <imgui/imgui.h>

INIT_SERIALIZABLE(ResourcePack)

void ResourcePack::gui()
{
    static ResourceInterface* currentResource = nullptr;

    ImGui::Begin("ResourcePack");
    char buf[1024] = {0};
    strcpy(buf, m_name.c_str());
    if(ImGui::InputText("Pack name", buf, 1024))
        m_name = buf;

    if(ImGui::Button("Save resource pack"))
    {
        std::fstream file;
        ObjectSaver saver;
        saver.addObject(this);
        file.open("data/" + m_name + ".pack", std::ios_base::out);
        saver.saveAscii(file);
        file.close();
    }
    if(ImGui::Button("Load resource pack"))
    {
        std::fstream file;
        file.open("data/" + m_name + ".pack", std::ios_base::in);
        ObjectLoader loader;
        loader.loadAscii(file);
        file.close();
        const std::vector<ResourcePack*>& packVec = loader.getObjects<ResourcePack>();
        for(ResourceInterface* res : m_resources)
            delete res;
        m_resources = packVec[0]->m_resources;
        delete packVec[0];
    }

    if(ImGui::Button("Add a texture"))
    {
        TextureResource* resource = new TextureResource();
        m_resources.push_back(resource);
    }

    if(ImGui::Button("Add a material"))
    {
        MaterialResource* resource = new MaterialResource();
        m_resources.push_back(resource);
    }

    for(ResourceInterface* res : m_resources)
    {
        if(ImGui::Button(res->m_name.c_str()))
            currentResource = res;
    }
    ImGui::End();

    if(currentResource != nullptr)
    {
        bool opened = true;
        ImGui::Begin("Resource Editor", &opened);

        char resBuf[1024] = {0};
        strcpy(resBuf, currentResource->m_name.c_str());
        if(ImGui::InputText("Name (should be unique)", resBuf, 1024))
            currentResource->m_name = resBuf;

        currentResource->gui();
        if(ImGui::Button("Delete resource"))
        {
            for(unsigned int i=0; i<m_resources.size(); ++i)
            {
                if(m_resources[i] == currentResource)
                {
                    m_resources.erase(m_resources.begin() + i);
                    delete currentResource;
                    currentResource = nullptr;
                }
            }
        }
        ImGui::End();
        if(!opened)
            currentResource = nullptr;
    }
}

INIT_SERIALIZABLE(TextureResource)

TextureResource::TextureResource() :
    m_texture(nullptr)
{
    m_name = "new texture";
    m_path = "myTexture.jpg";
    m_bitsPerPixel = 24;
    m_isVerticallyReversed = true;
    m_needsMipMaps = true;
}

TextureResource::~TextureResource()
{
    destroy();
}

void TextureResource::load(float & progress)
{
    progress = 0;
    Image* img = Loader::loadImage(m_path, m_bitsPerPixel, m_isVerticallyReversed);
    progress = 0.5;
    if(img == nullptr)
        return;
    m_texture = new Texture(img, m_needsMipMaps);
    RESOURCE_ADD(m_texture, Texture, m_name);
    delete img;
    progress = 1;
}

void TextureResource::destroy()
{
    if(m_texture != nullptr)
    {
        delete m_texture;
        m_texture = nullptr;
        RESOURCE_REMOVE(Texture, m_name);
    }
}

void TextureResource::gui()
{
    char buf[1024] = {0};
    strcpy(buf, m_path.c_str());
    if(ImGui::InputText("Image file", buf, 1024))
        m_path = buf;
    ImGui::InputInt("bits per pixel", &m_bitsPerPixel);
    ImGui::Checkbox("is vertically reversed", &m_isVerticallyReversed);
    ImGui::Checkbox("needs mipmaps", &m_needsMipMaps);
    ImGui::Text(m_texture == nullptr ? "Texture not loaded" : "Texture loaded");
    if(ImGui::Button(m_texture == nullptr ? "Load" : "Destroy"))
    {
        float temp;
        if(m_texture == nullptr)
            load(temp);
        else
            destroy();
    }
}

INIT_SERIALIZABLE(MaterialResource)

MaterialResource::MaterialResource() :
    m_material(nullptr)
{
    m_name = "new material";
    m_albedo = glm::vec3(0.9f);
    m_metallic = 0.2f;
    m_roughness = 0.8f;
    m_emission = glm::vec3(0);
    m_opacity = 1.f;
}

MaterialResource::~MaterialResource()
{
    destroy();
}

void MaterialResource::load(float & progress)
{
    m_material = new PBRMaterial();
    m_material->albedo = m_albedo;
    m_material->metallic = m_metallic;
    m_material->roughness = m_roughness;
    m_material->emission = m_emission;
    m_material->opacity = m_opacity;
    m_material->setTexture(PBRMaterial::ALBEDO_SLOT, RESOURCE_GET(Texture, m_albedoTexture));
    m_material->setTexture(PBRMaterial::METALLIC_SLOT, RESOURCE_GET(Texture, m_metallicTexture));
    m_material->setTexture(PBRMaterial::ROUGHNESS_SLOT, RESOURCE_GET(Texture, m_roughnessTexture));
    m_material->setTexture(PBRMaterial::EMISSION_SLOT, RESOURCE_GET(Texture, m_emissionTexture));
    m_material->setTexture(PBRMaterial::NORMALS_SLOT, RESOURCE_GET(Texture, m_normalTexture));
    m_material->setTexture(PBRMaterial::ALPHA_SLOT, RESOURCE_GET(Texture, m_alphaMaskTexture));
    RESOURCE_ADD(m_material, PBRMaterial, m_name);
    progress = 1;
}

void MaterialResource::destroy()
{
    if(m_material != nullptr)
    {
        delete m_material;
        m_material = nullptr;
        RESOURCE_REMOVE(PBRMaterial, m_name);
    }
}

void MaterialResource::gui()
{
    ImGui::Text("TODO");
}
