/*
RUDL - a C library wrapping SDL for use in Ruby.
Copyright (C) 2001-2003  Danny van Bruggen
Copyright (C) 2003-2004  Danny van Bruggen and Renne Nissinen

*/


/**
@file Fonts
@class TrueTypeFont

Using TrueTypeFonts is easy. You open a TTF file with @new specifying
its filename and size. You render text with it by calling @render, and you get a new
surface containing the image. If you use antialiasing and no background color, the
returned surface will have per-pixel alpha values, to retain the antialiasing after blitting
to a target surface.
*/


#include "rudl_ttf.h"

#ifdef HAVE_SDL_TTF_H
#include "rudl_video.h"
#endif

#define TTF_RAISE {rb_raise(classSDLError, TTF_GetError());}


void initTTF()
{
#ifdef HAVE_SDL_TTF_H
    if(!TTF_WasInit()){

        DEBUG_S("Starting TTF");
        if(TTF_Init()) TTF_RAISE;
    }
#endif
}

void quitTTF()
{
#ifdef HAVE_SDL_TTF_H
    if(TTF_WasInit()){

        DEBUG_S("Stopping TTF");
        TTF_Quit();
    }
#endif
}

void VALUE2SDL_COLOR(VALUE colorObject, SDL_Color* color)
{

    VALUE tmp;
    if(rb_obj_is_kind_of(colorObject, rb_cArray)){
        switch(RARRAY(colorObject)->len){
            case 4:
            case 3:

                tmp=rb_ary_entry(colorObject, 0);

                color->r=(Uint8)NUM2UINT(tmp),
                tmp=rb_ary_entry(colorObject, 1);

                color->g=(Uint8)NUM2UINT(tmp),
                tmp=rb_ary_entry(colorObject, 2);

                color->b=(Uint8)NUM2UINT(tmp);
                break;
            default:
                rb_raise(rb_eTypeError, "Need colorarray with 3 or 4 elements");
        }
    }else{
        rb_raise(rb_eTypeError, "Need a color array");
    }
}

#ifdef HAVE_SDL_TTF_H

/**
@section Class Methods
@method new( filename, size ) -> TrueTypeFont
Creates a new TrueTypeFont object.
@filename is the filename of a TTF file.
@size is the desired height of the font in pixels.
*/
static VALUE truetypefont_new(VALUE self, VALUE filename, VALUE size)
{
    TTF_Font *font;
    initTTF();
    font=TTF_OpenFont(STR2CSTR(filename), NUM2INT(size));
    if(!font)TTF_RAISE;
    return Data_Wrap_Struct(classTTF, 0, TTF_CloseFont, font);
}

TTF_Font* retrieveTTFPointer(VALUE obj)
{
    TTF_Font* font;
    Data_Get_Struct(obj, TTF_Font, font);
    return font;
}

/**
@section Instance Methods
@method render( text, antialias, foreground ) -> Surface
@method render( text, antialias, foreground, background ) -> Surface
Render the given @text onto a new image surface.
If @antialias is true, the edges of the font will be smoothed for a much cleaner look.

The @foreground and @background colors are both RGBA, but the alpha component is ignored if given.
If the background color is omitted, the text will have a transparent background.
*/
static VALUE truetypefont_render(int argc, VALUE* argv, VALUE self)
{
    TTF_Font* font = retrieveTTFPointer(self);
    bool aa;
    SDL_Surface* surf;
    SDL_Color foreg, backg;
    char* string;

    VALUE textValue, aaValue, fg_rgbaValue, bg_rgbaValue;

    switch(rb_scan_args(argc, argv, "31", &textValue, &aaValue, &fg_rgbaValue, &bg_rgbaValue)){
        case 4: VALUE2SDL_COLOR(bg_rgbaValue, &backg);
    }
    VALUE2SDL_COLOR(fg_rgbaValue, &foreg);

    aa=NUM2BOOL(aaValue);

    string=STR2CSTR(textValue);
    if(aa){
        if(argc==3){
            surf = TTF_RenderText_Blended(font, string, foreg);
        }else{
            surf = TTF_RenderText_Shaded(font, string, foreg, backg);
        }
    }else{
        surf = TTF_RenderText_Solid(font, string, foreg);
    }

    if(!surf) SDL_RAISE;

    if(!aa && argc==4) /*turn off transparancy*/
    {
        SDL_SetColorKey(surf, 0, 0);
        surf->format->palette->colors[0].r = backg.r;
        surf->format->palette->colors[0].g = backg.g;
        surf->format->palette->colors[0].b = backg.b;
    }

    return createSurfaceObject(surf);
}

/**
@method ascent -> Number
Returns the ascent for the font.
The ascent is the number of pixels from the font baseline to the top of the font.
*/
static VALUE truetypefont_ascent(VALUE self)
{
    return INT2NUM(TTF_FontAscent(retrieveTTFPointer(self)));
}

/**
@method bold? -> boolean
@method bold=( onOrOff ) -> self
Controls the bold attribute for the font.
Making the font bold does not work as well as you would expect.
*/
static VALUE truetypefont_bold_(VALUE self)
{
    return INT2BOOL((TTF_GetFontStyle(retrieveTTFPointer(self))&&TTF_STYLE_BOLD)!=0);
}

static VALUE truetypefont_bold__(VALUE self, VALUE onOrOff)
{
    TTF_Font* font = retrieveTTFPointer(self);
    int style;

    style = TTF_GetFontStyle(font);
    if(NUM2BOOL(onOrOff)){
        style |= TTF_STYLE_BOLD;
    }else{
        style &= ~TTF_STYLE_BOLD;
    }
    TTF_SetFontStyle(font, style);

    return self;
}

/**
@method italic? -> boolean
@method italic=( onOrOff ) -> self
Controls the italics attribute of the font.
*/
static VALUE truetypefont_italic_(VALUE self)
{
    return INT2BOOL((TTF_GetFontStyle(retrieveTTFPointer(self))&&TTF_STYLE_ITALIC)!=0);
}

static VALUE truetypefont_italic__(VALUE self, VALUE onOrOff)
{
    TTF_Font* font = retrieveTTFPointer(self);
    int style;

    style = TTF_GetFontStyle(font);
    if(NUM2BOOL(onOrOff)){
        style |= TTF_STYLE_ITALIC;
    }else{
        style &= ~TTF_STYLE_ITALIC;
    }
    TTF_SetFontStyle(font, style);

    return self;
}

/**
@method descent -> Number
Returns the descent for the font.
The descent is the number of pixels from the font baseline to the bottom of the font.
*/
static VALUE truetypefont_descent(VALUE self)
{
    return INT2NUM(TTF_FontDescent(retrieveTTFPointer(self)));
}

/**
@method h -> Number
Returns the average size of each glyph in the font.
*/
static VALUE truetypefont_h(VALUE self)
{
    return INT2NUM(TTF_FontHeight(retrieveTTFPointer(self)));
}

/**
@method linesize -> Number
Returns the linesize for the font.
Each font comes with its own recommendation for the number of spacing pixels between
each line of the font.
*/
static VALUE truetypefont_linesize(VALUE self)
{
    return INT2NUM(TTF_FontLineSkip(retrieveTTFPointer(self)));
}

/**
@method underline? -> boolean
@method underline=( onOrOff ) -> self
Controls the underline attribute of the font.
*/
static VALUE truetypefont_underline_(VALUE self)
{
    return INT2BOOL((TTF_GetFontStyle(retrieveTTFPointer(self))&&TTF_STYLE_UNDERLINE)!=0);
}

static VALUE truetypefont_underline__(VALUE self, VALUE onOrOff)
{
    TTF_Font* font = retrieveTTFPointer(self);
    int style;

    style = TTF_GetFontStyle(font);
    if(NUM2BOOL(onOrOff)){
        style |= TTF_STYLE_UNDERLINE;
    }else{
        style &= ~TTF_STYLE_UNDERLINE;
    }
    TTF_SetFontStyle(font, style);

    return self;
}

/**
@method size( text ) -> [w, h]
Returns the size in pixels that this text would need.
*/
static VALUE truetypefont_size(VALUE self, VALUE text)
{
    int w, h;
    TTF_SizeText(retrieveTTFPointer(self), STR2CSTR(text), &w, &h);
    return rb_ary_new3(2, INT2NUM(w), INT2NUM(h));
}
#endif

void initTrueTypeFontClasses()
{
#ifdef HAVE_SDL_TTF_H

    classTTF=rb_define_class_under(moduleRUDL, "TrueTypeFont", rb_cObject);
    rb_define_singleton_method(classTTF, "new", truetypefont_new, 2);
    rb_define_method(classTTF, "ascent", truetypefont_ascent, 0);
    rb_define_method(classTTF, "bold?", truetypefont_bold_, 0);
    rb_define_method(classTTF, "italic?", truetypefont_italic_, 0);
    rb_define_method(classTTF, "descent", truetypefont_descent, 0);
    rb_define_method(classTTF, "h", truetypefont_h, 0);

    rb_define_method(classTTF, "linesize", truetypefont_linesize, 0);
    rb_define_method(classTTF, "underline?", truetypefont_underline_, 0);
    rb_define_method(classTTF, "render", truetypefont_render, -1);
    rb_define_method(classTTF, "bold=", truetypefont_bold__, 1);
    rb_define_method(classTTF, "italic=", truetypefont_italic__, 1);
    rb_define_method(classTTF, "underline=", truetypefont_underline__, 1);
    rb_define_method(classTTF, "size", truetypefont_size, 1);


    // Backward compatability:
    rb_alias(classTTF, rb_intern("height"), rb_intern("h"));
    rb_eval_string(
            "module RUDL class TrueTypeFont             \n"
            "   def inspect                             \n"
            "       \"<TrueTypeFont: #{h}pix>\"  \n"
            "   end                                     \n"
            "end end                                    \n"
    );
#endif
}
