/**
* Project: VSXu: Realtime visual programming language, music/audio visualizer, animation tool and much much more.
*
* @see The Lesser GNU Public License (GPL)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public License
* for more details.
*
* You should have received a copy of the Lesser GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include    "FTFace.h"
#include    "FTFont.h"
#include    "FTGlyphContainer.h"
#include    "FTBBox.h"


FTFont::FTFont( const char* fontname)
:   face( fontname),
    glyphList(0)
{
    monospace = true;

    err = face.Error();
    if( err == 0)
    {
        glyphList = new FTGlyphContainer( &face);
    }
}


FTFont::FTFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes)
:   face( pBufferBytes, bufferSizeInBytes),
    glyphList(0)
{
  monospace = true;
    err = face.Error();
    if( err == 0)
    {
        glyphList = new FTGlyphContainer( &face);
    }
}


FTFont::~FTFont()
{
    delete glyphList;
}


bool FTFont::Attach( const char* filename)
{
    if( face.Attach( filename))
    {
        err = 0;
        return true;
    }
    else
    {
        err = face.Error();
        return false;
    }
}


bool FTFont::Attach( const unsigned char *pBufferBytes, size_t bufferSizeInBytes)
{
    if( face.Attach( pBufferBytes, bufferSizeInBytes))
    {
        err = 0;
        return true;
    }
    else
    {
        err = face.Error();
        return false;
    }
}


bool FTFont::FaceSize( const unsigned int size, const unsigned int res )
{
    charSize = face.Size( size, res);
    
    if( face.Error())
    {
        return false;
    }
    
    if( glyphList != NULL)
    {
        delete glyphList;
    }
    
    glyphList = new FTGlyphContainer( &face);
    return true;
}


unsigned int FTFont::FaceSize() const
{
    return charSize.CharSize();
}


bool FTFont::CharMap( FT_Encoding encoding)
{
    bool result = glyphList->CharMap( encoding);
    err = glyphList->Error();
    return result;
}


unsigned int FTFont::CharMapCount()
{
    return face.CharMapCount();
}


FT_Encoding* FTFont::CharMapList()
{
    return face.CharMapList();
}


float FTFont::Ascender() const
{
    return charSize.Ascender();
}


float FTFont::Descender() const
{
    return charSize.Descender();
}


void FTFont::BBox( const char* string,
                   float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
    FTBBox totalBBox;

    if((NULL != string) && ('\0' != *string))
    {
        const unsigned char* c = (unsigned char*)string;

        CheckGlyph( *c);

        totalBBox = glyphList->BBox( *c);
        float advance = glyphList->Advance( *c, *(c + 1));
        ++c;
            
        while( *c)
        {
            CheckGlyph( *c);
            FTBBox tempBBox = glyphList->BBox( *c);
            tempBBox.Move( FTPoint( advance, 0.0f, 0.0f));
            totalBBox += tempBBox;
            advance += glyphList->Advance( *c, *(c + 1));
            ++c;
        }
    }

    llx = totalBBox.lowerX;
    lly = totalBBox.lowerY;
    llz = totalBBox.lowerZ;
    urx = totalBBox.upperX;
    ury = totalBBox.upperY;
    urz = totalBBox.upperZ;
}


void FTFont::BBox( const wchar_t* string,
                   float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
    FTBBox totalBBox;

    if((NULL != string) && ('\0' != *string))
    {
        const wchar_t* c = string;

        CheckGlyph( *c);

        totalBBox = glyphList->BBox( *c);
        float advance = glyphList->Advance( *c, *(c + 1));
        ++c;

        while( *c)
        {
            CheckGlyph( *c);
            FTBBox tempBBox = glyphList->BBox( *c);
            tempBBox.Move( FTPoint( advance, 0.0f, 0.0f));
            totalBBox += tempBBox;
            advance += glyphList->Advance( *c, *(c + 1));
            ++c;
        }
    }

    llx = totalBBox.lowerX;
    lly = totalBBox.lowerY;
    llz = totalBBox.lowerZ;
    urx = totalBBox.upperX;
    ury = totalBBox.upperY;
    urz = totalBBox.upperZ;
}


float FTFont::Advance( const wchar_t* string)
{
    const wchar_t* c = string;
    float width = 0.0f;

    while( *c)
    {
        CheckGlyph( *c);
        width += glyphList->Advance( *c, *(c + 1));
        ++c;
    }

    return width;
}


float FTFont::Advance( const char* string)
{
    const unsigned char* c = (unsigned char*)string;
    float width = 0.0f;

    while( *c)
    {
        CheckGlyph( *c);
        width += glyphList->Advance( *c, *(c + 1));
        ++c;
    }
    
    return width;
}


void FTFont::Render( const char* string )
{
    const unsigned char* c = (unsigned char*)string;
    pen.x = 0; pen.y = 0;

    while( *c)
    {
        DoRender( *c, *(c + 1));
        ++c;
    }
}


void FTFont::Render( const wchar_t* string )
{
    const wchar_t* c = string;
    pen.x = 0; pen.y = 0;

    while( *c)
    {
        DoRender( *c, *(c + 1));
        ++c;
    }
}


void FTFont::DoRender( const unsigned int chr, const unsigned int nextChr)
{
    CheckGlyph( chr);

    FTPoint kernAdvance = glyphList->Render( chr, nextChr, pen);
    
//    pen.x += kernAdvance.x;
  if(monospace)
  {
    pen.x += kernAdvance.x;
  }  
    else
    pen.x += kernAdvance.x;
    
    pen.y += kernAdvance.y;
}


void FTFont::CheckGlyph( const unsigned int characterCode)
{
    if( NULL == glyphList->Glyph( characterCode))
    {
        unsigned int glyphIndex = glyphList->FontIndex( characterCode);
        glyphList->Add( MakeGlyph( glyphIndex), characterCode);
    }
}

