#include <fstream>
#include "BaseEffect.h"

#include <iostream>
#include <sstream>
#include <d3dcompiler.h>

BaseEffect::BaseEffect(ID3D11Device *devicePtr, const std::wstring &filePath) {
    const std::ifstream file(filePath);
    if (!file)
        std::wcout << L"File doesn't exist" << std::endl;

    m_EffectPtr = LoadEffect(devicePtr, filePath);
    m_TechniquePtr = m_EffectPtr->GetTechniqueByName("DefaultTechnique");

    if (!m_TechniquePtr->IsValid())
        std::wcout << L"Technique is not valid" << std::endl;

    m_MatWorldViewProjVariablePtr = m_EffectPtr->GetVariableByName("gWorldViewProj")->AsMatrix();
    if (!m_MatWorldViewProjVariablePtr->IsValid())
        std::wcout << L"gWorldViewProj Matrix is not valid" << std::endl;
}

BaseEffect::~BaseEffect() {
    m_EffectPtr->Release();
    m_EffectPtr = nullptr;
}

ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstring &filePath) {
    HRESULT result;
    ID3D10Blob *errorBlobPtr{nullptr};
    ID3DX11Effect *effectPtr;

    DWORD shaderFlags = 0;
#if defined( DEBUG ) || defined( _DEBUG )
    shaderFlags |= D3DCOMPILE_DEBUG;
    shaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif

    result = D3DX11CompileEffectFromFile(filePath.c_str(),
                                         nullptr,
                                         nullptr,
                                         shaderFlags,
                                         0,
                                         devicePtr,
                                         &effectPtr,
                                         &errorBlobPtr);

    if (FAILED(result)) {
        if (errorBlobPtr != nullptr) {
            const char *errorsPtr = static_cast<char *>(errorBlobPtr->GetBufferPointer());

            std::wstringstream ss;
            for (UINT i{}; i < errorBlobPtr->GetBufferSize(); i++)
                ss << errorsPtr[i];

            OutputDebugStringW(ss.str().c_str());

            errorBlobPtr->Release();
            errorBlobPtr = nullptr;
            return nullptr;
        } else {
            std::wstringstream ss;
            ss << "EffectLoader: Failed to CreateEffectFromFile!\nPath: " << filePath;
            std::wcout << ss.str() << std::endl;
            return nullptr;
        }
    }
    std::cout << "Effect loaded" << std::endl;
    return effectPtr;
}

void BaseEffect::SetWorldViewProjMatrix(const dae::Matrix &matrix) {
    m_MatWorldViewProjVariablePtr->SetMatrix(reinterpret_cast<const float *>(&matrix));
}

void BaseEffect::NextSamplingState() {

}

void BaseEffect::SetCameraPos(const dae::Vector3 &vector3) const {

}

void BaseEffect::SetMaterial(Material *material) {

}

void BaseEffect::SetWorldMatrix(const dae::Matrix& matrix) const {

}

void BaseEffect::ToggleNormals() {

}
