#include "../pch.h"
#include "Effect.h"

#include <fstream>

Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
        : BaseEffect(devicePtr, filePath) {

    m_LightPosVariablePtr = m_EffectPtr->GetVariableByName("gLightDirection")->AsVector();
    if(!m_LightPosVariablePtr->IsValid())
        std::wcout << L"gLightDirection Vector is not valid" << std::endl;

    m_SamplerVariablePtr = m_EffectPtr->GetVariableByName("gSampler")->AsSampler();
    if(!m_SamplerVariablePtr->IsValid())
        std::wcout << L"gSampler Sampler is not valid" << std::endl;

    m_MatWorldVariablePtr = m_EffectPtr->GetVariableByName("gWorldMatrix")->AsMatrix();
    if(!m_MatWorldVariablePtr->IsValid())
        std::wcout << L"gWorld Matrix is not valid" << std::endl;

    m_DiffuseMapVariablePtr = m_EffectPtr->GetVariableByName("gDiffuseMap")->AsShaderResource();
    if(!m_DiffuseMapVariablePtr->IsValid())
        std::wcout << L"gDiffuseMap ShaderResource is not valid" << std::endl;

    m_NormalMapVariablePtr = m_EffectPtr->GetVariableByName("gNormalMap")->AsShaderResource();
    if(!m_NormalMapVariablePtr->IsValid())
        std::wcout << L"gNormalMap ShaderResource is not valid" << std::endl;

    m_SpecularMapVariablePtr = m_EffectPtr->GetVariableByName("gSpecularMap")->AsShaderResource();
    if(!m_SpecularMapVariablePtr->IsValid())
        std::wcout << L"gSpecularMap ShaderResource is not valid" << std::endl;

    m_GlossMapVariablePtr = m_EffectPtr->GetVariableByName("gGlossMap")->AsShaderResource();
    if(!m_GlossMapVariablePtr->IsValid())
        std::wcout << L"gGlossMap ShaderResource is not valid" << std::endl;

    m_CameraPosVariablePtr = m_EffectPtr->GetVariableByName("gCameraPosition")->AsVector();
    if(!m_CameraPosVariablePtr->IsValid())
        std::wcout << L"gCameraPos Vector is not valid" << std::endl;

    m_LightColorVariablePtr = m_EffectPtr->GetVariableByName("gLightColor")->AsVector();
    if(!m_LightColorVariablePtr->IsValid())
        std::wcout << L"gLightColor Vector is not valid" << std::endl;

    m_UseNormalMapVariablePtr = m_EffectPtr->GetVariableByName("gUseNormal")->AsScalar();
    if(!m_UseNormalMapVariablePtr->IsValid())
        std::wcout << L"gUseNormalMap Scalar is not valid" << std::endl;

    m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap);


    constexpr int vectorSize{ 4 };
    constexpr float lightDirection[vectorSize]{ .577f, -.577f, .577f, 0.f };
    m_LightPosVariablePtr->SetFloatVector(lightDirection);

    constexpr float lightColor[vectorSize]{ 1.f, 1.f, 1.f, 1.f };
    m_LightColorVariablePtr->SetFloatVector(lightColor);

    this->InitSamplers(devicePtr);
}

Effect::~Effect() {
    m_MatWorldVariablePtr->Release();
    m_MatWorldVariablePtr = nullptr;

    m_DiffuseMapVariablePtr->Release();
    m_DiffuseMapVariablePtr = nullptr;

    m_NormalMapVariablePtr->Release();
    m_NormalMapVariablePtr = nullptr;

    m_SpecularMapVariablePtr->Release();
    m_SpecularMapVariablePtr = nullptr;

    m_GlossMapVariablePtr->Release();
    m_GlossMapVariablePtr = nullptr;

    m_CameraPosVariablePtr->Release();
    m_CameraPosVariablePtr = nullptr;

    m_LightPosVariablePtr->Release();
    m_LightPosVariablePtr = nullptr;

    m_LightColorVariablePtr->Release();
    m_LightColorVariablePtr = nullptr;

    m_UseNormalMapVariablePtr->Release();
    m_UseNormalMapVariablePtr = nullptr;

    m_SamplerVariablePtr->Release();
    m_SamplerVariablePtr = nullptr;

    for(auto sampler : m_SamplerStates){
        sampler->Release();
    }
}

void Effect::SetWorldMatrix(const dae::Matrix &world) const {
    m_MatWorldVariablePtr->SetMatrix(reinterpret_cast<const float*>(&world));
}

void Effect::SetMaterial(Material* material) {
    if(material->diffuseTexturePtr)
        m_DiffuseMapVariablePtr->SetResource(material->diffuseTexturePtr->GetSrv());
    if(material->normalTexturePtr)
        m_NormalMapVariablePtr->SetResource(material->normalTexturePtr->GetSrv());
    if(material->specularTexturePtr)
        m_SpecularMapVariablePtr->SetResource(material->specularTexturePtr->GetSrv());
    if(material->glossTexturePtr)
        m_GlossMapVariablePtr->SetResource(material->glossTexturePtr->GetSrv());
}


void Effect::SetCameraPos(const dae::Vector3 &pos) const {
    m_CameraPosVariablePtr->SetFloatVector(reinterpret_cast<const float*>(&pos));
}

void Effect::NextSamplingState() {
    switch(m_TechniqueType){
        case TechniqueType::Point:
            m_TechniqueType = TechniqueType::Linear;
            std::cout << "Linear" << std::endl;
            break;
        case TechniqueType::Linear:
            m_TechniqueType = TechniqueType::Anisotropic;
            std::cout << "Anisotropic" << std::endl;
            break;
        case TechniqueType::Anisotropic:
            m_TechniqueType = TechniqueType::Point;
            std::cout << "Point" << std::endl;
            break;
    }
    m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
}

void Effect::ToggleNormals() {
    m_UseNormalMap = !m_UseNormalMap;
    m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap);
}

void Effect::InitSamplers(ID3D11Device *devicePtr) {
    D3D11_SAMPLER_DESC samplerDesc{};
    samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;

    devicePtr->CreateSamplerState(&samplerDesc, &m_SamplerStates[static_cast<int>(TechniqueType::Anisotropic)]);

    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    devicePtr->CreateSamplerState(&samplerDesc, &m_SamplerStates[static_cast<int>(TechniqueType::Linear)]);

    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
    devicePtr->CreateSamplerState(&samplerDesc, &m_SamplerStates[static_cast<int>(TechniqueType::Point)]);

    m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
}
