#pragma once

#include "FontGlyph.h"

#include <d2d1_1.h>
#include <dwrite.h>

#include <memory>

static const IID IID_IGlyphOutlineGeometrySink = { 0xaaf6ab8d, 0xd6cf, 0x4a3b, { 0xa6, 0x7a, 0x12, 0xf1, 0x42, 0xe0, 0x6b, 0xb9 } };
class IGlyphOutlineGeometrySink : public IDWriteGeometrySink
{
public:
    virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
};

class GlyphOutlineGeometrySink :public IGlyphOutlineGeometrySink
{
public:
    GlyphOutlineGeometrySink();

    // IUnknown
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();

    static IUnknown* Create();

    // IDWriteGeometrySink aka ID2D1SimplifiedGeometrySink
    STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);

    STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);

    STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);

    STDMETHOD_(void, AddLines)(_In_reads_(pointsCount) CONST D2D1_POINT_2F* points, UINT32 pointsCount);

    STDMETHOD_(void, AddBeziers)(_In_reads_(beziersCount) CONST D2D1_BEZIER_SEGMENT* beziers, UINT32 beziersCount);

    STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);

    STDMETHOD(Close)();

    // IGlyphOutlineGeometrySink
    std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
private:
    std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
    long mRefCount{ 0 };
};


static const IID IID_IOffScreenTextRenderer = { 0xa43b0c49, 0x6080, 0x4731, { 0xa8, 0x72, 0x61, 0x50, 0x47, 0x3, 0x78, 0x10 } };
class IOffScreenTextRenderer : public IDWriteTextRenderer
{
    virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
};

class OffScreenTextRenderer :public IOffScreenTextRenderer
{
public:
    // IUnknown
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();

    static IUnknown* Create();

    STDMETHOD(DrawGlyphRun)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
        _In_ DWRITE_GLYPH_RUN const* glyphRun, _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, _In_opt_ IUnknown* clientDrawingEffect);

    STDMETHOD(DrawUnderline)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_UNDERLINE const* underline, 
        _In_opt_ IUnknown* clientDrawingEffect);

    STDMETHOD(DrawStrikethrough)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_STRIKETHROUGH const* strikethrough,
        _In_opt_ IUnknown* clientDrawingEffect);

    STDMETHOD(DrawInlineObject)(_In_opt_ void* clientDrawingContext, FLOAT originX, FLOAT originY, _In_ IDWriteInlineObject* inlineObject,
        BOOL isSideways, BOOL isRightToLeft, _In_opt_ IUnknown* clientDrawingEffect);

    STDMETHOD(IsPixelSnappingDisabled)(_In_opt_ void* clientDrawingContext, _Out_ BOOL* isDisabled);

    STDMETHOD(GetCurrentTransform)(_In_opt_ void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform);

    STDMETHOD(GetPixelsPerDip)(_In_opt_ void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip);

    std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
private:
    std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
    long mRefCount{ 0 };
};