#include "DirectX2dIntegration.h"

#include "Window.h"
#include "Widget.h"
#include "DirectXPainter.h"
#include "DrawingContext.h"

#include "DirectXInterface.h"
#include "DirectX2dInterface.h"

#include <d3d11.h>
#include <d3d11on12.h>
#include <d2d1_3.h>
#include <d2d1_1.h>

DirectX2dIntegration::DirectX2dIntegration(mt::Window* window, DirectXInterface* dxInterface, UINT frameCount)
    :   mDxInterface(dxInterface),
        mWindow(window),
        mFrameCount(frameCount)
{
    mDx2dInterface = dxInterface->getD2dInterface();
}

ID3D11Resource* const* DirectX2dIntegration::getD11on12WrappedBackBuffer() const
{
    return mWrappedBackBuffers[mFrameIndex].GetAddressOf();
}

ID2D1Bitmap1* DirectX2dIntegration::getD2dRenderTarget() const
{
    return mD2dRenderTargets[mFrameIndex].Get();
}

void DirectX2dIntegration::render()
{
    // Acquire our wrapped render target resource for the current back buffer.
    mDxInterface->get11On12Device()->AcquireWrappedResources(getD11on12WrappedBackBuffer(), 1);

    // Render text directly to the back buffer.
    mDx2dInterface->getContext()->SetTarget(getD2dRenderTarget());

    mWindow->getDrawingContent()->getPainter()->paint();

    // Release our wrapped render target resource. Releasing 
    // transitions the back buffer resource to the state specified
    // as the OutState when the wrapped resource was created.
    mDxInterface->get11On12Device()->ReleaseWrappedResources(getD11on12WrappedBackBuffer(), 1);

    // Flush to submit the 11 command list to the shared command queue.
    mDxInterface->getD3d11DeviceContext()->Flush();
}

void DirectX2dIntegration::clearBuffers()
{
    for (auto& buffer : mWrappedBackBuffers)
    {
        buffer.Reset();
    }
    mWrappedBackBuffers.clear();

    for (auto& buffer : mD2dRenderTargets)
    {
        buffer.Reset();
    }
    mD2dRenderTargets.clear();

    mDx2dInterface->getContext()->SetTarget(nullptr);
    mDxInterface->getD3d11DeviceContext()->Flush();
}

void DirectX2dIntegration::wrapBuffer(ID3D12Resource* renderTarget)
{
    mWrappedBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D11Resource>());

    D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
    mDxInterface->get11On12Device()->CreateWrappedResource(renderTarget, &d3d11Flags,
        D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&mWrappedBackBuffers[mWrappedBackBuffers.size()-1]));

    float dpiX{ 96.0 };
    float dpiY{ 96.0 };
    //mDx2dInterface->getFactory()->GetDesktopDpi(&dpiX, &dpiY);
    const auto pixel_format = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
    const auto bitmap_props = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, pixel_format, dpiX, dpiY);

    mD2dRenderTargets.push_back(Microsoft::WRL::ComPtr<ID2D1Bitmap1>());
    Microsoft::WRL::ComPtr<IDXGISurface> surface;
    mWrappedBackBuffers[mWrappedBackBuffers.size() - 1].As(&surface);
    mDx2dInterface->getContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmap_props, &mD2dRenderTargets[mD2dRenderTargets.size()-1]);
}

void DirectX2dIntegration::updateBackbufferIndex(UINT idx)
{
    mFrameIndex = idx;
}
