#include "Text.h"

int64                Text::_refCount         = 0;
ID2D1Factory*        Text::_d2dFactory       = 0;
IWICImagingFactory*  Text::_wicFactory       = 0;
IDWriteFactory*      Text::_dwriteFactory    = 0;


Text::Text(const wchar_t* text)
: Transform(), _text(text), _textFormat(0), _textLayout(0), _resourceHandle(0),
_maxWidth(128.0f), _maxHeight(16.0f), _dirty(true), _fontName(L"Arial"),
_fontSize(16.0f), _fontColor(L"ffffff"), _fontStyle(FONT_STYLE_REGULAR),
_textAlignment(H_ALIGN_LEFT | V_ALIGN_TOP), _width(0.0f), _height(0.0f)
{
    HRESULT hr = S_OK;

    if (_refCount == 0) {
        CoInitialize(NULL);

        // Create D2D factory
        hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &_d2dFactory);
        if (SUCCEEDED(hr)) {
            // Create a WIC factory
            hr = CoCreateInstance(
                CLSID_WICImagingFactory,
                NULL,
                CLSCTX_INPROC_SERVER,
                IID_IWICImagingFactory,
                reinterpret_cast<void **>(&_wicFactory)
                );
        }
        if (SUCCEEDED(hr)) {
            // Create DWrite factory
            hr = DWriteCreateFactory(
                DWRITE_FACTORY_TYPE_SHARED,
                __uuidof(_dwriteFactory),
                reinterpret_cast<IUnknown **>(&_dwriteFactory)
                );
        }
    }

    hr = _dwriteFactory->CreateTextFormat(
        L"Arial",
        NULL,
        DWRITE_FONT_WEIGHT_NORMAL,
        DWRITE_FONT_STYLE_NORMAL,
        DWRITE_FONT_STRETCH_NORMAL,
        16.0f,
        L"", //locale
        &_textFormat
        );

    _textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
    _textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);

    _refCount++;
}


Text::~Text()
{
    _refCount--;

    if (_refCount == 0) {
        // TODO: release all factories and resources
        CoUninitialize();
    }
}

bool Text::isDirty()
{
    return _dirty;
}

void Text::setDirty(bool dirty)
{
    _dirty = dirty;
}

std::wstring& Text::getString()
{
    return _text;
}

const wchar_t* Text::getText() const
{
    if (_text.empty())
        return 0;
    else
        return _text.c_str();
}

void Text::setText(const wchar_t* text)
{
    _text = text;
    recreateTextLayout();
    _dirty = true;
}

float Text::getWidth()
{
    return _width;
}

float Text::getHeight()
{
    return _height;
}

float Text::getMaxWidth()
{
    return _maxWidth;
}

float Text::getMaxHeight()
{
    return _maxHeight;
}

void Text::setMaxWidth(float maxWidth)
{
    _maxWidth = maxWidth;
    recreateTextLayout();
    _dirty = true;
}

void Text::setMaxHeight(float maxHeight)
{
    _maxHeight = maxHeight;
    recreateTextLayout();
    _dirty = true;
}

ID2D1Factory* Text::getD2DFactory()
{
    return _d2dFactory;
}

IWICImagingFactory* Text::getWICFactory()
{
    return _wicFactory;
}

IDWriteFactory* Text::getDWriteFactory()
{
    return _dwriteFactory;
}

IDWriteTextFormat* Text::getTextFormat()
{
    return _textFormat;
}

IDWriteTextLayout* Text::getTextLayout()
{
    return _textLayout;
}


void* Text::getResourceHandle()
{
    return _resourceHandle;
}

void Text::setResourceHandle(void* resourceHandle)
{
    _resourceHandle = resourceHandle;
}

void Text::recreateTextLayout()
{
    DWRITE_TEXT_RANGE textRange = {0, UINT32_MAX};

    if (_textAlignment & Text::H_ALIGN_LEFT)
        _textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
    else if (_textAlignment & Text::H_ALIGN_CENTER)
        _textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
    else if (_textAlignment & Text::H_ALIGN_RIGHT)
        _textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING);

    if (_textAlignment & Text::V_ALIGN_TOP)
        _textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
    else if (_textAlignment & Text::V_ALIGN_CENTER)
        _textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
    else if (_textAlignment & Text::V_ALIGN_BOTTOM)
        _textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_FAR);

    
    if (_textLayout != 0) {
        _textLayout->Release();
        _textLayout = 0;
    }

    _dwriteFactory->CreateTextLayout(
        _text.c_str(),
        (UINT)_text.length(),
        _textFormat,
        _maxWidth,
        _maxHeight,
        &_textLayout
        );


    if (_fontStyle & FONT_STYLE_BOLD) {
        _textLayout->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, textRange);
    }
    if (_fontStyle & FONT_STYLE_ITALIC) {
        _textLayout->SetFontStyle(DWRITE_FONT_STYLE_ITALIC, textRange);
    }
    if (_fontStyle & FONT_STYLE_UNDERLINE) {
        _textLayout->SetUnderline(TRUE, textRange);
    }
    if (_fontStyle & FONT_STYLE_STRIKETHROUGH) {
        _textLayout->SetStrikethrough(TRUE, textRange);
    }

    _textLayout->SetFontSize(_fontSize, textRange);

    _textLayout->SetFontFamilyName(_fontName.c_str(), textRange);

    DWRITE_TEXT_METRICS metrics;
    _textLayout->GetMetrics(&metrics);

    _width = metrics.width;
    _height = metrics.height;
}


void Text::setFont(const wchar_t* font, const wchar_t* color, float size, uint32 style, uint32 alignment)
{
    _fontName = font;
    _fontColor = color;
    _fontSize = size;
    _fontStyle = style;
    _textAlignment = alignment;

    recreateTextLayout();

    _dirty = true;
}

const wchar_t* Text::getFontName()
{
    return _fontName.c_str();
}

const wchar_t* Text::getFontColor()
{
    return _fontColor.c_str();
}

float Text::getFontSize()
{
    return _fontSize;
}

uint32 Text::getFontStyle()
{
    return _fontStyle;
}

uint32 Text::getTextAlignment()
{
    return _textAlignment;
}