/*  text.c: (c) 2002 sibn

    This file is part of Gwiz.

    GWiz is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    GWiz 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
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with GWiz; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gwiz.h"
#include "prefsdat.h"
#include "uiloop.h"
#include "text.h"
#include "menus.h"
#include "keynames.h"
#include "joystick.h"

#define TEXT_TOP 0
#define TEXT_RIGHT 1
#define TEXT_BOTTOM 2
#define TEXT_LEFT 3

const SDL_Color fg = { 0xff, 0xff, 0xff, 0 };
const SDL_Color bg = { 0x00, 0x00, 0x00, 0 };

extern GwizApp gwiz;

void InitGwizFonts (void)
{
    char *freeme;
    
    if (TTF_Init() < 0)    /* Initialize the TTF engine */
	BailCall ("text.c ", SDL_GetError());
    atexit (TTF_Quit);
    
    LoadBorders(); /* Load the images used in drawing text borders */
    
    freeme = MakePath(PKGDATADIR, "/NIMBU26.TTF");
    gwiz.font.face = TTF_OpenFont(freeme, gwiz.font.ptsize);
    if (gwiz.font.face == NULL)
	BailCall ("text.c: ", SDL_GetError());
    gwiz.font.height = TTF_FontHeight (gwiz.font.face);
    /* could really use any glyph, wouldn't matter */
    TTF_GlyphMetrics(gwiz.font.face, 'e', &gwiz.font.minx, &gwiz.font.maxx,
		     &gwiz.font.miny, &gwiz.font.maxy, &gwiz.font.width);
    while (gwiz.font.maxline < 800-16-gwiz.font.width)
	gwiz.font.maxline += gwiz.font.width;
    gwiz.font.maxline /= gwiz.font.width;
    
    Sfree (freeme);
}

/* Create text box that FITS width, height- it does not measure w, h! */
SDL_Surface *NewTextBox (int width, int height)
{
    SDL_Surface *box;
    SDL_Rect dest, src;
    int w = width+16;
    int h = height+16;
    int i;
    
    box = NewGwizSurface (w, h);

    src.x = 0;
    src.y = 0;
    src.w = 7;
    src.h = 7;
    dest.x = 0;
    dest.y = 0;
    dest.w = 7;
    dest.h = 7;
    SDL_BlitSurface (gwiz.tbord[0], &src, box, &dest);
    dest.x = w-7;
    SDL_BlitSurface (gwiz.tbord[2], &src, box, &dest);
    dest.y = h-7;
    dest.x = w-7;
    SDL_BlitSurface (gwiz.tbord[7], &src, box, &dest);
    dest.x = 0;
    SDL_BlitSurface (gwiz.tbord[5], &src, box, &dest);
    
    src.w = 1;
    dest.x = 7;
    dest.y = 0;
    dest.h = 7;
    dest.w = 1;
    for (i = 7; i < w-7; i++)
	{
	    SDL_BlitSurface (gwiz.tbord[1], &src, box, &dest);
	    dest.x++;
	}
    dest.y = h-7;
    dest.x = 7;
    for (i = 7; i < w-7; i++)
	{
	    SDL_BlitSurface (gwiz.tbord[6], &src, box, &dest);
	    dest.x++;
	}
    
    dest.x = 0;
    dest.y = 7;
    src.h = 1;
    src.w = 7;
    for (i = 7; i < h-7; i++)
	{
	    SDL_BlitSurface (gwiz.tbord[3], &src, box, &dest);
	    dest.y++;
	}
    dest.x = w-7;
    dest.y = 7;
    for (i = 7; i < h-7; i++)
	{
	    SDL_BlitSurface (gwiz.tbord[4], &src, box, &dest);
	    dest.y++;
	}

    return (box);    
}

SDL_Surface *NewTextMsg (char *msg)
{
    SDL_Surface *textbox;
    SDL_Surface *textmsg;
    SDL_Rect dest;
    
    textmsg = GwizRenderText (msg);
    textbox = NewTextBox (textmsg->w, textmsg->h);
    
    dest.x = textbox->w/2 - textmsg->w/2;
    dest.y = textbox->h/2 - textmsg->h/2;
    dest.h = textmsg->h;
    dest.w = textmsg->w;
    
    SDL_BlitSurface (textmsg, NULL, textbox, &dest);
	SDL_FreeSurface (textmsg);
	return (textbox);
}

SDL_Surface *NewVertTextMsg (char **msg, int align) /* FIXME: alignment? */
{
    SDL_Surface *area;
    SDL_Surface *lines[64]; /* "64 ought to be enough for anybody" ;) */
    SDL_Rect dest;
    int i = 0;
    int members = 0;
    int widest = 0;
    
    while ((msg[i] != NULL) && (i-1 < 64))
	{
	    members = i+1;
	    lines[i] = GwizRenderText (msg[i]);
	    if (lines[i]->w > widest)
		widest = lines[i]->w;
	    i++;
	}
    
    area = NewGwizSurface (widest, gwiz.font.height * members);
    
    if (area == NULL)
	BailCall ("text.c: unable to make vertical text msg: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    
    for (i = 0; i < members; i++)
	{
	    dest.w = lines[i]->w;
	    SDL_BlitSurface (lines[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (lines[i]);
	}
    
    return (area);
}

void LoadBorders (void)
{
    char *pix = PIXMAPSDIR;
    char *freeme;
    
    freeme = MakePath (pix, "/texttl.png");
    gwiz.tbord[0] = IMG_Load (freeme);
    if (gwiz.tbord[0] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textt.png");
    gwiz.tbord[1] = IMG_Load (freeme);
    if (gwiz.tbord[1] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/texttr.png");
    gwiz.tbord[2] = IMG_Load (freeme);
    if (gwiz.tbord[2] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textl.png");
    gwiz.tbord[3] = IMG_Load (freeme);
    if (gwiz.tbord[3] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textr.png");
    gwiz.tbord[4] = IMG_Load (freeme);
    if (gwiz.tbord[4] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textbl.png");
    gwiz.tbord[5] = IMG_Load (freeme);
    if (gwiz.tbord[5] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textb.png");
    gwiz.tbord[6] = IMG_Load (freeme);
    if (gwiz.tbord[6] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
    
    freeme = MakePath (pix, "/textbr.png");
    gwiz.tbord[7] = IMG_Load (freeme);
    if (gwiz.tbord[7] == NULL)
	BailCall ("text.c: ", SDL_GetError());
    Sfree (freeme);
}

void Ouch(void)
{
    /* Idea is simple enough.  Print "Ouch!" to the canvas center */
    SDL_Rect drect;
    SDL_Surface *text;
    SDL_Surface *textbox;
    text = GwizRenderText("Ouch!");
    textbox = NewTextBox(text->w, text->h);
    
    drect.x = 800/2 - text->w/2-8;
    drect.y = 600/2 - text->h/2-8;
    drect.h = text->h;
    drect.w = text->w;
    SDL_BlitSurface (textbox, NULL, gwiz.canvas, &drect);
    SDL_UpdateRects (gwiz.canvas, 1, &drect);
    drect.x = 800/2 - text->w/2;
    drect.y = 600/2 - text->h/2;
    SDL_BlitSurface (text, NULL, gwiz.canvas, &drect);
    SDL_UpdateRects (gwiz.canvas, 1, &drect);
    OuchLoop();
    
    SDL_FreeSurface(text);
    SDL_FreeSurface(textbox);
}

void OuchLoop(void)
{
    SDL_Event event;
    while (SDL_WaitEvent (&event) != 0)
	{
	    /* deprecated, going away soon. FIXME */
	    switch (event.type)
		{
		case SDL_KEYDOWN:
		    return;
		case SDL_JOYBUTTONDOWN:
		    CheckJoy();
		    if (gwiz.joy.enabled)
			return;
		case SDL_KEYUP:
		    break;
		}
	}
}

void MsgBox (char *msg)
{
    SDL_Surface *box;
    SDL_Surface *text;
    SDL_Surface *displace;
    SDL_Rect dest;

    text = GwizRenderText (msg);
    box = NewTextBox (text->w, text->h);
    displace = NewGwizSurface (box->w, box->h);

    dest.x = gwiz.tbord[0]->w;
    dest.y = gwiz.tbord[0]->h;
    dest.h = text->h;
    dest.w = text->w;
    SDL_BlitSurface (text, NULL, box, &dest);

    dest.x = gwiz.canvas->w/2 - box->w/2;
    dest.y = gwiz.canvas->h/2 - box->h/2;
    dest.h = box->h;
    dest.w = box->w;
    SDL_BlitSurface (gwiz.canvas, &dest, displace, NULL);

    SDL_BlitSurface (box, NULL, gwiz.canvas, &dest);
    SDL_Flip (gwiz.canvas);

    WaitForAnyKey();

    SDL_BlitSurface (displace, NULL, gwiz.canvas, &dest);
    SDL_Flip (gwiz.canvas);
    SDL_FreeSurface (box);
    SDL_FreeSurface (text);
    SDL_FreeSurface (displace);
}

void InitCommonNums (void)
{
    int i;
    char cn[3]; /* common numbers are only two digits long. */
    for (i = 0; i < 26; i++)
	{
	    if (i < 10)
		/* Right-align */
		snprintf (cn, sizeof(char)*3, " %d", i);
	    else
		snprintf (cn, sizeof(char)*3, "%d", i);
	    gwiz.number[i] = GwizRenderText (cn);
	    if (gwiz.number[i] == NULL)
		BailCall("text.c: unable to render common numbers: ",
			 cn);
	}
}

void InitClassPix (void)
{
    char *strings[] = {
	"Fighter",
	"Mage   ",
	"Cleric ",
	"Thief  ",
	"Wizard ",
	"Samurai",
	"Lord   ",
	"Ninja  "
    };
    int i;
    SDL_Surface *classpix[8];
    
    for (i = 0; i < 8; i++)
        {
	    /* Render text */
	    classpix[i] = GwizRenderText(strings[i]);
	    if (classpix[i] == NULL)
		BailCall ("text.c: unable to render text: ",
			  strings[i]);
	    
	    /* Convert it for fast blits */
	    gwiz.classpix[i] = SDL_DisplayFormat (classpix[i]);
	    if (gwiz.classpix[i] == NULL)
		BailCall ("text.c: unable to convert text: ",
			  strings[i]);
	    SDL_FreeSurface (classpix[i]);
	}
}

void NewTextEntry (char *title, char *inputmsg, int inputlength)
{
    SDL_Surface *box;
    SDL_Surface *prompt;
    SDL_Surface *entry;
    SDL_Surface *screen;
    SDL_Rect dest;
    SDL_Rect text;
    SDL_Event event;
    int inputwidth;
    int i = 0;
    int breakout = FALSE;
    
    for (i = 0; i < inputlength; i++)
	inputmsg[i] = '\0';
    
    inputwidth = inputlength * gwiz.font.width;
    
    prompt = GwizRenderText (title);
    entry = NewGwizSurface (gwiz.font.width*(inputlength-1), gwiz.font.height);

    if (prompt->w > entry->w)
	i = prompt->w;
    else
	i = entry->w;
    
    box = NewTextBox (i, gwiz.font.height*2);
    dest.x = 8;
    dest.y = 8;
    dest.h = prompt->h;
    dest.w = prompt->w;
    SDL_BlitSurface (prompt, NULL, box, &dest);
    dest.y += gwiz.font.height;
    SDL_BlitSurface (entry, NULL, box, &dest);
    text.x = dest.x;
    text.y = dest.y;
    text.h = dest.h;
    text.w = dest.w;
    screen = SDL_DisplayFormat (gwiz.canvas);
    dest.x = gwiz.canvas->w/2 - box->w/2;
    dest.y = gwiz.canvas->h/2 - box->h/2;
    dest.h = box->h;
    dest.w = box->w;
    SDL_BlitSurface (box, NULL, gwiz.canvas, &dest);
    
    i = 0;
    while (SDL_WaitEvent (&event) != 0)
	{
	    SDL_keysym key;
	    switch (event.type)
	        {
		case SDL_KEYDOWN:
		    key = event.key.keysym;
		    if (event.key.keysym.sym == SDLK_BACKSPACE)
			if (i > 0)
			    {
				i--;
				inputmsg[i] = ' ';
				inputmsg[i+1] = '\0';
			    }
		    if ((event.key.keysym.sym == SDLK_RETURN) &&
			(i != 0)) /* make sure there's something there */
			breakout = TRUE;

		    if ((key.sym >= SDLK_SPACE) && (key.sym <= SDLK_z) &&
			(i < inputlength-1))
			{
			    if ((key.mod & KMOD_SHIFT) &&
				(key.sym > SDLK_a-1) &&
				(key.sym < SDLK_z+1))
				key.sym -= 0x20;
			    if ((key.mod & KMOD_SHIFT) && 
				(key.sym > SDLK_EXCLAIM)  &&
				(key.sym < SDLK_AT))
				key.sym = ShiftNumberRow (key.sym);
			    inputmsg[i] = key.sym;
			    inputmsg[i+1] = '\0';
			    i++;
			}
		    break;
		case SDL_KEYUP:
		    break;
		case SDL_QUIT:
		    VerifyQuit();
		}
	    if (inputmsg[0] == '\0')
		{
		    inputmsg[0] = ' ';
		    inputmsg[1] = '\0';
		}
	    if (breakout)
		break;
	    entry = GwizRenderText(inputmsg);
	    SDL_BlitSurface (entry, NULL, box, &text);
	    SDL_BlitSurface (box, NULL, gwiz.canvas, &dest);
	    SDL_Flip (gwiz.canvas);
	    SDL_FreeSurface (entry); /* This gets rerendered a lot */
	}
    /* Cleanup artifacts */
    SDL_BlitSurface (screen, NULL, gwiz.canvas, NULL);
    SDL_FreeSurface (box);
    SDL_FreeSurface (prompt);
    SDL_FreeSurface (screen);
}

SDLKey ShiftNumberRow (SDLKey key)
{
#ifndef SDLK_PERCENT /* SDL is uh, screwed up and doesn't include this */
#define SDLK_PERCENT 37
#endif
    switch (key)
	{
	case SDLK_0:
	    return (SDLK_RIGHTPAREN);
	case SDLK_1:
	    return (SDLK_EXCLAIM);
	case SDLK_2:
	    return (SDLK_AT);
	case SDLK_3:
	    return (SDLK_HASH);
	case SDLK_4:
	    return (SDLK_DOLLAR);
	case SDLK_5:
	    return (SDLK_PERCENT);
	case SDLK_6:
	    return (SDLK_CARET);
	case SDLK_7:
	    return (SDLK_AMPERSAND);
	case SDLK_8:
	    return (SDLK_ASTERISK);
	case SDLK_9:
	    return (SDLK_LEFTPAREN);
	case SDLK_QUOTE:
	    return (SDLK_QUOTEDBL);
	case SDLK_COMMA:
	    return (SDLK_LESS);
	case SDLK_PERIOD:
	    return (SDLK_GREATER);
	case SDLK_SLASH:
	    return (SDLK_QUESTION);
	case SDLK_SEMICOLON:
	    return (SDLK_COLON);
	case SDLK_EQUALS:
	    return (SDLK_PLUS);
	case SDLK_MINUS:
	    return (SDLK_UNDERSCORE);
	default:
	    /* we want to ignore any unrecognized sym */
	    break;
	}
    return (key);
}

SDL_Surface *GwizRenderText(char *msg)
{
    SDL_Surface *area = NULL;
    if (gwiz.font.aa > 0)
	area = TTF_RenderText_Shaded(gwiz.font.face, msg, fg, bg);
    else if (gwiz.font.aa == 0)
	area = TTF_RenderText_Solid(gwiz.font.face, msg, fg);
    if (area == NULL)
	BailCall ("text.c: unable to render text: ", SDL_GetError());
    return (area);
}
