#include "FreeTypeGlyphVector.h"
#include <assert.h>


FreeTypeGlyphVector::FreeTypeGlyphVector(FT_Face face, const _TCHAR* text) : glyphs(NULL)
{
    assert(text);
    this->library = face->glyph->library;
    const int len = _tcslen(text);
    this->text = (_TCHAR*) ::malloc(sizeof(_TCHAR) * (len + 1));
    this->sizeMetrics = face->size->metrics;
    if (this->text)
    {
	::_tcscpy(this->text, text);
	performDefaultLayout(face);
    }
}

FreeTypeGlyphVector::~FreeTypeGlyphVector()
{
    disposeAllGlyphs();
    free(this->text);
}

void FreeTypeGlyphVector::disposeAllGlyphs()
{
    const int numGlyphs = getNumGlyphs();
    FT_Library library = getLibrary();

    if (this->glyphs)
    {
	for (int i = 0; i < numGlyphs; ++i)
	{
	    FT_Bitmap_Done(library, &this->glyphs[i].bitmap);
	    FT_Outline_Done(library, &this->glyphs[i].outline);
	}
	delete this->glyphs;
        this->glyphs = NULL;
    }
}

void FreeTypeGlyphVector::updateLogicalBounds()
{
    const int numGlyphs = getNumGlyphs();
    FT_Vector v = getGlyphPosition(0);
    FT_Pos minX = v.x;
    FT_Pos maxX = v.x;
    int bottomY = v.y + this->sizeMetrics.descender;
    int topY = bottomY + this->sizeMetrics.height;
    FT_Pos minY = bottomY;
    FT_Pos maxY = topY;

    for (int i = 1; i <= numGlyphs; ++i)
    {
	v = getGlyphPosition(i);
	if (v.x > maxX)
	{
	    maxX = v.x;
	}
	else if (v.x < minX)
	{
	    minX = v.x;
	}
	bottomY = v.y + this->sizeMetrics.descender;
	topY = bottomY + this->sizeMetrics.height;
	if (topY > maxY)
	{
	    maxY = topY;
	}
	if (bottomY < minY)
	{
	    minY = bottomY;
	}
    }
    this->x = minX;
    this->y = minY;
    this->width = maxX - minX;
    this->height = maxY - minY;
}


void FreeTypeGlyphVector::getLogicalBounds(FT_Pos* x, FT_Pos* y, FT_Pos* width, FT_Pos* height) const
{
    // getLogicalBounds()は、setGlyphPosition()の操作を無視する(?)
    // http://d.hatena.ne.jp/freebeans/20090121/p1
    // updateLogicalBounds()
    *x = this->x;
    *y = this->y;
    *width = this->width;
    *height = this->height;
}

void FreeTypeGlyphVector::getVisualBounds(FT_Pos* x, FT_Pos* y, FT_Pos* width, FT_Pos* height) const
{
    const int numGlyphs = getNumGlyphs();

    FT_Pos minX = INT_MAX;
    FT_Pos maxX = INT_MIN;
    FT_Pos minY = INT_MAX;
    FT_Pos maxY = INT_MIN;

    for (int i = 0; i < numGlyphs; ++i)
    {
	FT_Vector v = getGlyphPosition(i);
	FT_Bitmap bitmap = getBitmap(i);
	FT_Int bitmapLeft = getBitmapLeft(i);
	FT_Int bitmapTop = getBitmapTop(i);

	FT_Pos bottomY = v.y - ((bitmap.rows - bitmapTop) << 6);
	FT_Pos topY = v.y + (bitmapTop<<6);
	FT_Pos leftX = v.x + (bitmapLeft<<6);
	FT_Pos rightX = leftX + (bitmap.width<<6);

	if (leftX < minX)
	{
	    minX = leftX;
	}
	if (rightX > maxX)
	{
	    maxX = rightX;
	}
	if (topY > maxY)
	{
	    maxY = topY;
	}
	if (bottomY < minY)
	{
	    minY = bottomY;
	}
    }
    *x = minX;
    *y = minY;
    *width = maxX - minX;
    *height = maxY - minY + (1<<6); // 高さに1を加算（不要？）
}

void FreeTypeGlyphVector::getGlyphLogicalBounds(int glyphIndex, FT_Vector* p1, FT_Vector* p2, FT_Vector* p3, FT_Vector* p4) const
{
    FT_Vector v = getGlyphPosition(glyphIndex);
    FT_Pos minX = v.x;
    FT_Pos maxX = minX + this->glyphs[glyphIndex].advance.x;

    int bottomY = v.y + this->sizeMetrics.descender;
    int topY = bottomY + this->sizeMetrics.height + this->glyphs[glyphIndex].advance.y;

    p1->x = minX;
    p1->y = bottomY;

    p2->x = maxX;
    p2->y = bottomY;

    p3->x = maxX;
    p3->y = topY;

    p4->x = minX;
    p4->y = topY;
}

void FreeTypeGlyphVector::getGlyphVisualBounds(int glyphIndex, FT_Vector* p1, FT_Vector* p2, FT_Vector* p3, FT_Vector* p4) const
{
    FT_Vector v = getGlyphPosition(glyphIndex);
    FT_Bitmap bitmap = getBitmap(glyphIndex);
    FT_Int bitmapLeft = getBitmapLeft(glyphIndex);
    FT_Int bitmapTop = getBitmapTop(glyphIndex);

    FT_Pos bottomY = v.y - ((bitmap.rows - bitmapTop) << 6);
    FT_Pos topY = v.y + (bitmapTop<<6) + (1<<6); // 高さに1を加算（不要？）
    FT_Pos leftX = v.x + (bitmapLeft<<6);
    FT_Pos rightX = leftX + (bitmap.width<<6);

    p1->x = leftX;
    p1->y = bottomY;

    p2->x = rightX;
    p2->y = bottomY;

    p3->x = rightX;
    p3->y = topY;

    p4->x = leftX;
    p4->y = topY;
}

/**
 * デフォルトのレイアウト処理を行う
 */
void FreeTypeGlyphVector::performDefaultLayout(FT_Face face)
{
    FT_GlyphSlot slot = face->glyph;
    FT_Long use_kerning = FT_HAS_KERNING(face);
    FT_UInt previous = 0;
    FT_Pos pen_x = 0;
    int error;
    const int text_len = _tcslen(text);

    disposeAllGlyphs();
    const int numGlyphs = getNumGlyphs();

    this->glyphs = new Glyph[numGlyphs + 1]; // 最後の文字の次のグリフも含む
    if (! glyphs)
    {
        return;
    }

    int i;
    Glyph* glyph = NULL;
    for (i = 0; i < text_len; ++i) {
	_TCHAR c = text[i];
	glyph = &this->glyphs[i];
	FT_UInt glyph_index = FT_Get_Char_Index(face, c);
	if (use_kerning && previous && glyph_index)
	{
	    FT_Vector delta;
	    error = FT_Get_Kerning( face, previous, glyph_index, ft_kerning_default, &delta );
	    pen_x += delta.x;
	}
	glyph->position.x = pen_x;
	glyph->position.y = 0;

	error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME );
	if (error)
	{
	    continue;
	}

	glyph->advance = slot->advance;

	// Load the bitmap image.
	FT_Bitmap_New(&glyph->bitmap);
	error = FT_Bitmap_Copy(slot->library, &slot->bitmap, &glyph->bitmap);
	if (! error)
	{
	    glyph->bitmapLeft = slot->bitmap_left;
	    glyph->bitmapTop = slot->bitmap_top;
	    pen_x += slot->advance.x;
	    previous = glyph_index;

	    if (! slot->outline.n_contours)
	    {
		// reload outline data.
		FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME | FT_LOAD_NO_BITMAP);
	    }
	    FT_Outline outline = slot->outline;
	    error = FT_Outline_New(slot->library, outline.n_points, outline.n_contours, &glyph->outline);
	    if (! error)
	    {
		error = FT_Outline_Copy(&outline, &glyph->outline);
		if (error)
		{
		    continue;
		}
		FT_Outline_Translate(&glyph->outline, glyph->position.x, glyph->position.y);
	    }
	}
    } 
    // 最後の文字の次の場所も入れる
    glyph = &this->glyphs[i];
    glyph->position.x = pen_x;
    glyph->position.y = 0;

    updateLogicalBounds();
}

/**
 * creates a new native bitmap mask to draw this GlyphVector.
 *
 * @param index	glyph index in this GlyphVector
 * @return	a bitmap handle.
 */
HBITMAP FreeTypeGlyphVector::createBitmapMask(int index)
{
    FT_Bitmap bitmap = getBitmap(index);
    unsigned char* bits = NULL;
    if (bitmap.pitch & 0x01)
    {
	// ワード境界に配置しなおす
	int padding = abs(sizeof(WORD) - bitmap.pitch);
	bits = (unsigned char*) ::calloc(1, (bitmap.pitch + padding) * bitmap.rows);

	if (bits)
	{
	    unsigned char* src = bitmap.buffer;
	    unsigned char* dest = bits;
	    for (int i = 0; i < bitmap.rows; ++i)
	    {
		for (int j = 0; j < bitmap.pitch; ++j)
		{
		    *dest++ = *src++;
		}
		dest += padding;
	    }
	}
    }

    HBITMAP hMaskBitmap = CreateBitmap(bitmap.width, bitmap.rows, 1, 1, (bits ? bits : bitmap.buffer));
    free(bits);
    
    return hMaskBitmap;
}

bool FreeTypeGlyphVector::equals(FreeTypeGlyphVector* gv)
{
    // ToDo: implement
    return gv == this;
}
