#include "DirectXPainter.h"

#include "DrawingContext.h"
#include "DrawingSurface.h"
#include "Scene.h"
#include "SceneItem.h"
#include "SceneModel.h"
#include "SceneText.h"

#include "TriMesh.h"

#include "FontsManager.h"
#include "FontGlyph.h"
#include "TextData.h"

#include "DirectXShaderProgram.h"
#include "DirectXMeshPainter.h"
#include "DirectXTextPainter.h"
#include "DirectX2dPainter.h"
#include "DirectXMesh.h"
#include "DirectXInterface.h"
#include "DirectX2dInterface.h"

#include <wincodec.h>
#include "Win32WicImage.h"

#include "File.h"

#include <windows.h>

DirectXPainter::DirectXPainter(DrawingContext* context)
    :   AbstractPainter(context),
        mMeshPainter(std::make_unique<DirectXMeshPainter>()),
        mTextPainter(std::make_unique<DirectXTextPainter>()),
        m2dPainter(std::make_unique<DirectX2dPainter>())
{

}

DirectXMeshPainter* DirectXPainter::getMeshPainter() const
{
    return mMeshPainter.get();
}

void DirectXPainter::setDxInterface(DirectXInterface* dxInterface)
{
    mRawDxInterface = dxInterface;
    resetPainters();
}

DirectXInterface* DirectXPainter::getDxInterface() const
{
    if (mDxInterface)
    {
        return mDxInterface.get();
    }
    else
    {
        return mRawDxInterface;
    }
}

void DirectXPainter::initializeMesh()
{
    mMeshPainter->initializeD3d();
}

void DirectXPainter::updateMesh()
{
    mMeshPainter->updateBuffers(mDrawingContext);
}

void DirectXPainter::initializeDxInterface()
{
    mDxInterface = std::make_unique<DirectXInterface>();

    auto backing_image = mDrawingContext->getSurface()->getImage();
    auto wic_bitmap = dynamic_cast<Win32WicImage*>(backing_image->getPlatformImage())->getBitmap();

    mDxInterface->getD2dInterface()->initialize(wic_bitmap);

    resetPainters();
}

void DirectXPainter::resetPainters()
{
    m2dPainter->setD2dInterface(getDxInterface()->getD2dInterface());
    mTextPainter->setD2dInterface(getDxInterface()->getD2dInterface());
    mMeshPainter->setDxInterface(getDxInterface());
}

void DirectXPainter::paint()
{
    if (!getDxInterface())
    {
        initializeDxInterface();
    }

    auto scene = mDrawingContext->getSurface()->getScene();

    m2dPainter->startDrawing();
    m2dPainter->clearBackground(scene->getBackgroundColor());

    for (const auto item : scene->getItems())
    {
        if (!item->isVisible())
        {
            continue;
        }

        if (item->getType() == SceneItem::Type::MODEL)
        {
            auto model = dynamic_cast<SceneModel*>(item);
            if (model->getGeometry())
            {
                m2dPainter->paint(model);
            }
        }
        else if (item->getType() == SceneItem::Type::TEXT)
        {
            auto text = dynamic_cast<SceneText*>(item);
            mTextPainter->paint(text, mDrawingContext);
        }

    }

    m2dPainter->finishDrawing();
}

void DirectXPainter::paintBackground(const D3D12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList)
{
    const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
    commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
}

void DirectXPainter::paintMesh(ID3D12GraphicsCommandList* commandList)
{
    mMeshPainter->updateCommandList(commandList);
}

bool DirectXPainter::supportsGeometryPrimitives() const
{
    return true;
}
