#define _TEXT_INTERNAL_
#include "commun.h"
#include <stdio.h>
#include <stdarg.h>

void vFormatString(char *dest, const char *format, va_list arg_ptr);

//The font, 8 pixels wide, using 1-bit per pixel.
const unsigned char txt_tailles[] =
{
	4,
	4,
	5,
	8,
	7,
	8,
	8,
	3,
	5,
	5,
	7,
	8,
	4,
	5,
	4,
	5,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	7,
	5,
	5,
	8,
	8,
	8,
	6,
	8,
	8,
	8,
	8,
	8,
	7,
	6,
	8,
	8,
	5,
	5,
	8,
	6,
	8,
	8,
	8,
	7,
	8,
	8,
	8,
	7,
	8,
	8,
	8,
	8,
	7,
	8,
	5,
	5,
	5,
	8,
	7,
	7,
	7,
	7,
	6,
	7,
	7,
	4,
	7,
	7,
	3,
	4,
	7,
	3,
	8,
	7,
	7,
	7,
	7,
	5,
	6,
	4,
	7,
	7,
	8,
	7,
	7,
	6,
	7,
	5,
	7,
	8,
	8,
};

const unsigned char txt_texte[] =
{
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	4,
	4,
	4,
	4,
	4,
	4,
	0,
	4,
	0,
	0,
	10,
	10,
	10,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	80,
	80,
	252,
	40,
	40,
	126,
	20,
	20,
	0,
	0,
	8,
	8,
	60,
	10,
	10,
	28,
	40,
	40,
	30,
	8,
	8,
	0,
	140,
	146,
	82,
	76,
	32,
	160,
	144,
	16,
	0,
	0,
	0,
	12,
	18,
	18,
	76,
	82,
	34,
	98,
	156,
	0,
	0,
	2,
	2,
	2,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	8,
	4,
	4,
	2,
	2,
	2,
	2,
	2,
	4,
	4,
	8,
	2,
	4,
	4,
	8,
	8,
	8,
	8,
	8,
	4,
	4,
	2,
	8,
	42,
	28,
	42,
	8,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	16,
	16,
	16,
	254,
	16,
	16,
	16,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	4,
	4,
	4,
	2,
	0,
	0,
	0,
	0,
	0,
	14,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	4,
	4,
	0,
	0,
	16,
	16,
	8,
	8,
	4,
	4,
	2,
	2,
	1,
	1,
	0,
	0,
	28,
	34,
	34,
	34,
	34,
	34,
	34,
	28,
	0,
	0,
	0,
	8,
	14,
	8,
	8,
	8,
	8,
	8,
	62,
	0,
	0,
	0,
	28,
	34,
	32,
	16,
	8,
	4,
	2,
	62,
	0,
	0,
	0,
	28,
	34,
	32,
	24,
	32,
	32,
	34,
	28,
	0,
	0,
	0,
	16,
	24,
	20,
	18,
	17,
	63,
	16,
	16,
	0,
	0,
	0,
	62,
	2,
	2,
	30,
	32,
	32,
	34,
	28,
	0,
	0,
	0,
	24,
	4,
	2,
	30,
	34,
	34,
	34,
	28,
	0,
	0,
	0,
	62,
	32,
	16,
	16,
	8,
	8,
	4,
	4,
	0,
	0,
	0,
	28,
	34,
	34,
	28,
	34,
	34,
	34,
	28,
	0,
	0,
	0,
	28,
	34,
	34,
	34,
	60,
	32,
	16,
	12,
	0,
	0,
	0,
	0,
	0,
	4,
	4,
	0,
	0,
	4,
	4,
	0,
	0,
	0,
	0,
	0,
	4,
	4,
	0,
	0,
	4,
	4,
	4,
	2,
	0,
	0,
	0,
	96,
	24,
	6,
	24,
	96,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	254,
	0,
	254,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	12,
	48,
	192,
	48,
	12,
	0,
	0,
	0,
	0,
	14,
	16,
	16,
	8,
	4,
	4,
	0,
	4,
	0,
	0,
	0,
	248,
	4,
	114,
	74,
	74,
	74,
	178,
	4,
	120,
	0,
	0,
	24,
	24,
	36,
	36,
	36,
	126,
	66,
	66,
	0,
	0,
	0,
	30,
	34,
	34,
	62,
	66,
	66,
	66,
	62,
	0,
	0,
	0,
	120,
	132,
	2,
	2,
	2,
	2,
	132,
	120,
	0,
	0,
	0,
	62,
	66,
	130,
	130,
	130,
	130,
	66,
	62,
	0,
	0,
	0,
	62,
	2,
	2,
	62,
	2,
	2,
	2,
	62,
	0,
	0,
	0,
	62,
	2,
	2,
	30,
	2,
	2,
	2,
	2,
	0,
	0,
	0,
	120,
	132,
	2,
	2,
	226,
	130,
	132,
	120,
	0,
	0,
	0,
	66,
	66,
	66,
	126,
	66,
	66,
	66,
	66,
	0,
	0,
	0,
	14,
	4,
	4,
	4,
	4,
	4,
	4,
	14,
	0,
	0,
	0,
	14,
	8,
	8,
	8,
	8,
	8,
	8,
	7,
	0,
	0,
	0,
	66,
	34,
	18,
	10,
	14,
	18,
	34,
	66,
	0,
	0,
	0,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	62,
	0,
	0,
	0,
	198,
	198,
	170,
	170,
	146,
	146,
	130,
	130,
	0,
	0,
	0,
	70,
	70,
	74,
	74,
	82,
	82,
	98,
	98,
	0,
	0,
	0,
	56,
	68,
	130,
	130,
	130,
	130,
	68,
	56,
	0,
	0,
	0,
	30,
	34,
	34,
	34,
	30,
	2,
	2,
	2,
	0,
	0,
	0,
	56,
	68,
	130,
	130,
	130,
	130,
	68,
	56,
	32,
	192,
	0,
	30,
	34,
	34,
	34,
	30,
	18,
	34,
	66,
	0,
	0,
	0,
	60,
	66,
	2,
	12,
	48,
	64,
	66,
	60,
	0,
	0,
	0,
	127,
	8,
	8,
	8,
	8,
	8,
	8,
	8,
	0,
	0,
	0,
	66,
	66,
	66,
	66,
	66,
	66,
	66,
	60,
	0,
	0,
	0,
	66,
	66,
	66,
	36,
	36,
	36,
	24,
	24,
	0,
	0,
	0,
	146,
	146,
	170,
	170,
	170,
	170,
	68,
	68,
	0,
	0,
	0,
	66,
	66,
	36,
	24,
	24,
	36,
	66,
	66,
	0,
	0,
	0,
	65,
	34,
	20,
	8,
	8,
	8,
	8,
	8,
	0,
	0,
	0,
	126,
	64,
	32,
	16,
	8,
	4,
	2,
	126,
	0,
	0,
	14,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	14,
	1,
	1,
	2,
	2,
	4,
	4,
	8,
	8,
	16,
	16,
	0,
	14,
	8,
	8,
	8,
	8,
	8,
	8,
	8,
	8,
	8,
	14,
	0,
	16,
	40,
	68,
	130,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	127,
	4,
	8,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	28,
	32,
	60,
	34,
	34,
	60,
	0,
	0,
	2,
	2,
	2,
	30,
	34,
	34,
	34,
	34,
	30,
	0,
	0,
	0,
	0,
	0,
	28,
	34,
	2,
	2,
	34,
	28,
	0,
	0,
	32,
	32,
	32,
	60,
	34,
	34,
	34,
	34,
	60,
	0,
	0,
	0,
	0,
	0,
	28,
	34,
	62,
	2,
	34,
	28,
	0,
	0,
	12,
	2,
	2,
	15,
	2,
	2,
	2,
	2,
	2,
	0,
	0,
	0,
	0,
	0,
	60,
	34,
	34,
	34,
	34,
	60,
	32,
	28,
	2,
	2,
	2,
	30,
	34,
	34,
	34,
	34,
	34,
	0,
	0,
	2,
	0,
	0,
	2,
	2,
	2,
	2,
	2,
	2,
	0,
	0,
	4,
	0,
	0,
	6,
	4,
	4,
	4,
	4,
	4,
	4,
	3,
	2,
	2,
	2,
	34,
	18,
	10,
	14,
	18,
	34,
	0,
	0,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	2,
	0,
	0,
	0,
	0,
	0,
	110,
	146,
	146,
	146,
	146,
	146,
	0,
	0,
	0,
	0,
	0,
	30,
	34,
	34,
	34,
	34,
	34,
	0,
	0,
	0,
	0,
	0,
	28,
	34,
	34,
	34,
	34,
	28,
	0,
	0,
	0,
	0,
	0,
	30,
	34,
	34,
	34,
	34,
	30,
	2,
	2,
	0,
	0,
	0,
	60,
	34,
	34,
	34,
	34,
	60,
	32,
	32,
	0,
	0,
	0,
	26,
	6,
	2,
	2,
	2,
	2,
	0,
	0,
	0,
	0,
	0,
	28,
	2,
	6,
	24,
	16,
	14,
	0,
	0,
	0,
	2,
	2,
	15,
	2,
	2,
	2,
	2,
	12,
	0,
	0,
	0,
	0,
	0,
	34,
	34,
	34,
	34,
	34,
	60,
	0,
	0,
	0,
	0,
	0,
	34,
	34,
	20,
	20,
	8,
	8,
	0,
	0,
	0,
	0,
	0,
	146,
	146,
	170,
	170,
	68,
	68,
	0,
	0,
	0,
	0,
	0,
	34,
	20,
	8,
	8,
	20,
	34,
	0,
	0,
	0,
	0,
	0,
	34,
	20,
	20,
	20,
	8,
	8,
	8,
	4,
	0,
	0,
	0,
	30,
	16,
	8,
	4,
	2,
	30,
	0,
	0,
	48,
	8,
	8,
	8,
	8,
	6,
	8,
	8,
	8,
	8,
	48,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	4,
	6,
	8,
	8,
	8,
	8,
	48,
	8,
	8,
	8,
	8,
	6,
	0,
	0,
	0,
	0,
	140,
	146,
	98,
	0,
	0,
	0,
	0,
	0,
	254,
	2,
	2,
	2,
	2,
	2,
	2,
	254,
	0,
	0,
};

u8 EWRAM_DATA txt_buffer[600 * 32];
u32 *txt_adresse = NULL;

//Width, height of the sprite plane (in tiles).
int txt_largeur = 0, txt_hauteur = 0;

//x*hauteur*8 = x<<4 because hauteur=16

void Texte_init(u32 x, u32 y, u32 largeur, u32 hauteur, u16 *map, u32 offset)
{
	u32 i, j;
	for (j = 0; j < largeur; j++)
	{
		for (i = 0; i < hauteur; i++)
		{
			*(map + 32 * (i + y) + (j + x)) = (offset++) | (15 << 12);
		}
	}
}

void DessTexteBG3(u32 x, u32 y, char *texte)
{
	while (*texte)
	{
		*((u16 *)SCREEN_BASE_BLOCK(28) + y * 32 + x) = ((*texte) - 32) | 15 << 12;
		x++;
		texte++;
	}
}

void DessTexteSprites(u32 x, u32 y, char *texte)
{
	u32 til;
	til = AjSprite(charset_tiles, sizeof(charset_tiles) << 1);
	y *= 8;
	x *= 8;
	while (*texte)
	{
		if (*texte != ' ')
			CreeObjetStandardHUD(x, y, til + (*texte) - 32, 14, TAILLE_8x8);
		x += 8;
		texte++;
	}
}

void DessTexte(int x, int y, char *texte)
{

	/*    if (!gblDebogage)
	return;*/
	if (gblLI->ei.using_bg3)
		DessTexteSprites(x, y, texte);
	else
		DessTexteBG3(x, y, texte);
}

void printf_xy(int x, int y, const char *format, ...)
{
	char vbuf[100];
	va_list arg_ptr;

	va_start(arg_ptr, format);
	vFormatString(vbuf, format, arg_ptr);
	DessTexte(x, y, vbuf);
}

void Message(int ligne, const char *format, ...)
{
	char vbuf[100];
	va_list arg_ptr;

	va_start(arg_ptr, format);
	vFormatString(vbuf, format, arg_ptr);
	DessTexte(0, ligne, "                              ");
	DessTexte(0, ligne, vbuf);
}

void Alerte(const char *format, ...)
{
	char vbuf[100];
	va_list arg_ptr;

	//    if (fade)
	//        return;
	InitSprites();
	va_start(arg_ptr, format);
	vFormatString(vbuf, format, arg_ptr);
	DessTexte(0, 10, "                              ");
	DessTexte(0, 10, vbuf);
	if (!(REG_KEYS & KEY_L))
	{
		if (gblLI->ei.using_bg3)
		{
			CopieSprites();
			CopieDMA(MonOAM, OAM, 1024 >> 2, DMA_32im);
		}

		while ((REG_KEYS & KEY_SELECT));
		while (!(REG_KEYS & KEY_SELECT));
		while ((REG_KEYS & KEY_SELECT));
	}
}

void Bloque(const char *format, ...)
{
	int j;
	char vbuf[100];
	va_list arg_ptr;

	va_start(arg_ptr, format);
	vFormatString(vbuf, format, arg_ptr);
	DessTexte(0, 0, "                              ");
	DessTexte(0, 0, vbuf);
	for (j = 0; j < 30; j++)
		AttendVSync();
}

void Attention(const char *format, ...)
{
	u32 j;
	char vbuf[100];
	va_list arg_ptr;

	va_start(arg_ptr, format);
	vFormatString(vbuf, format, arg_ptr);
	DessTexte(0, 0, "                              ");
	DessTexte(0, 0, vbuf);
	for (j = 0; j < 10; j++)
		AttendVSync();
	if (gblLI->ei.using_bg3)
	{
		CopieSprites();
		CopieDMA(MonOAM, OAM, 1024 >> 2, DMA_32im);
	}

	while (!(REG_KEYS & KEY_SELECT));
}

//#define HORZ(x) ((x)*20*8)

//#define VERT(y) ((y)*20)
#define HORZ(x) ((x) * 16 * 8)
#define VERT(y) ((y) * 16)

//Store a pattern 'motif' using mask 'masque' at location pointed to by 'adr'
#define MODIF(adr, masque, motif)        (*(adr) = (*(adr) & masque) | motif)

//Draw a box. The position must be 8-pixels boundary. 3rd and 4th parameter are the size

//in pixels, and 1st and 2nd parameter are the starting position.
void DessBoite(u32 x0, u32 y0, u32 larg, u32 haut)
{
	u32 *adr, *adrbase, *adrfond;
	u32 i, j;
	const int motif_gauche = 0x44444441, motif_milieu = 0x44444444, motif_droite = 0x14444444, motif_bord = 0x11111111,
		motif_bord_gauche = 0x11111111, motif_bord_droite = 0x11111111;

	adr = txt_adresse + y0 + VERT(x0 &~7);
	adrfond = txt_adresse + y0 + haut + VERT(x0 &~7);

	adrbase = adr;
	*(adr - HORZ(1)) = motif_bord_gauche;
	*(adrfond - HORZ(1)) = motif_bord_gauche;
	for (i = 0; i < larg; i += 8)
	{
		*(adr + HORZ(i >> 3)) = motif_bord;
		*(adrfond + HORZ(i >> 3)) = motif_bord;
	}

	*(adr + HORZ(i >> 3)) = motif_bord_droite;
	*(adrfond + HORZ(i >> 3)) = motif_bord_droite;

	adr = adrbase + 1;
	j = y0 + 1;
	for (; j < y0 + haut; j++)
	{
		*(adr - HORZ(1)) = motif_gauche;
		for (i = 0; i < larg >> 3; i++)
			*(adr + HORZ(i)) = motif_milieu;
		*(adr + HORZ(i)) = motif_droite;
		adr++;
	}
}

//Enlevable de l'IWRAM!!!!
void DessParagraphe(u32 x, u32 y, const char *chne, u32 couleur)
{
	u32 x0 = x, xfictif;
	const char *chnefictive;
	while (*chne)
	{
		if (*chne == ' ')
		{
			xfictif = x;
			chnefictive = chne;
			do
			{
				xfictif += txt_tailles[(*chnefictive++) - 32];
				if (xfictif > (txt_largeur << 3))
					goto saute_ligne;
			}
			while (*chnefictive && *chnefictive != ' ' && *chnefictive != '\n');
		}

		if (x + txt_tailles[*chne - 32] > (txt_largeur << 3) || *chne == '\n')
		{
saute_ligne:
			if (*chne == '\n' || *chne == ' ')
				chne++;
			x = x0, y += HAUTEUR;
			if (y + HAUTEUR > (txt_hauteur << 3))
				break;
			else
				continue;
		}

		EcritCar(x, y, txt_texte + HAUTEUR * (*chne - 32), couleur);
		x += txt_tailles[*chne - 32];
		chne++;
	}
}

void ErreurFatale(const char *endroit, const char *format, ...)
{
	u32 fond = 0, i, j;
	char str[300];
	u32 dispcnt, oldBlendCnt;
	va_list arg_ptr;

	dispcnt = REG_DISPCNT;

	//   REG_DISPCNT = (VIDEO_MODE0 | OBJ_ENABLED | 0x40);
	//Remplit la VRAM de vide
	_memset((void *) CHAR_BASE_BLOCK(4), &fond, 30 * 20 * 32);

	//Crée un plan de sprites
	InitSprites();
	for (i = 0; i < 30; i++)
	{
		for (j = 0; j < 4; j++)
		{
			CreeObjet(objetsUtilises,                //Numéro d'objet
				(j + i * 4) * 4 + 1,        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
				8 + i * 8,                        //Position X initiale
				16 + j * 32,                        //Position Y initiale
				0,                //Mode (alpha-blend)
				2,                //Forme (0=carrée)
				1,                //Taille
				0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
				0,                //Numéro de palette si 16 couleurs
				0,                //Priorité
				0,                //Retournement vertical
				0,                //Retournement horizontal
				0,                //Mode mosaïque (?)
				0,                //Rotation
				0,                //N° de rotation
				0);                //Double-taille (pour rotation)
			objetsUtilises++;
		}
	}

	CopieDMA(MonOAM, OAM, 1024 >> 2, DMA_32im);

	DesactiveInterruptions();        //Le jeu est terminé
	oldBlendCnt = REG_BLDCNT;
	REG_BLDY = 10;
	REG_BLDCNT = 0x3fef;

	//   Texte_init(0,0,30,20,(void*)SCREEN_BASE_BLOCK(28),1);            //Fullscreen
	BG_PALETTE[0] = RGB(0, 0, 24); //Fond bleu
	SPRITE_PALETTE[0x01] = RGB(31, 31, 31);
	SPRITE_PALETTE[0x05] = RGB(31, 0, 0);
	SPRITE_PALETTE[0x04] = RGB(0, 0, 0);
	SPRITE_PALETTE[0x02] = RGB(31, 31, 0);
	SPRITE_PALETTE[0x03] = RGB(0, 31, 0);
	SPRITE_PALETTE[0x06] = RGB(31, 24, 0);

	//Paramétrage du buffer texte
	txt_adresse = (void *)CHAR_BASE_BLOCK(4) + 32;
	txt_hauteur = 16;
	txt_largeur = 29;

	DessBoite(72, 0, 74 + 6, 15);
	DrawText(73 + 1, 3, "Erreur fatale!", 1);

	//   DessParagraphe(0,26,"Une erreur grave est apparue.",2);
	DessParagraphe(0, 26 + 5, "Veuillez reporter ceci au programmeur:", 3);

	//   sprintf(str,"Code d'erreur: %02x",error_num);
	//   Exec(DrawText,10,42+3*HAUTEUR+8,"Lieu de l'erreur:",1);
	DrawText(0, 26 + 1 * HAUTEUR + 8, endroit, 1);

	DrawText(0, 26 + 3 * HAUTEUR + 11 - 6, "Informations supplementaires:", 6);

	//Arguments supplémentaires
	va_start(arg_ptr, format);
	vsprintf(str, format, arg_ptr);
	DessParagraphe(0, 26 + 4 * HAUTEUR + 14 - 6, str, 1);

	//   REG_BG3VOFS=0;
	while (REG_KEYS & KEY_START);
	while (!(REG_KEYS & KEY_START));
	ancienRegTouches = REG_KEYS;
	initInterrupt();
	REG_DISPCNT = dispcnt;
	REG_BLDCNT = oldBlendCnt;
}

void vFormatString(char *dest, const char *format, va_list arg_ptr)
{
	char charBuffer[100];
	const char *formatEnd = format;

	// Trouve la fin de la chaîne
	while (*formatEnd)
		formatEnd++;

	// Parcourt la chaîne de format
	while (format < formatEnd)
	{
		if (*format == '%')
		{
			char padChar = ' ';
			s32 nPositions = 0;
			u32 index = 0;

			format++;
			if (*format == '0' || *format == ' ')
				padChar = *format++;

			// Récupère le nombre de positions
			while (*format >= '0' && *format <= '9')
				nPositions = nPositions * 10 + (*format++) - '0';

			switch (*format++)
			{
				// Integer
				case 'i':
				{
					// Récupère un argument
					int value = va_arg(arg_ptr, int);
					bool bNegative = false;

					// Termine la chaîne et commence par la fin
					index = numberof(charBuffer) - 1;
					charBuffer[index] = 0;

					// Prend une position pour le signe -
					if (value < 0)
						value = -value, bNegative = true, nPositions--;

					// Convertit l'entier en chaîne
					if (value == 0)
						charBuffer[--index] = '0', nPositions--;
					else
					{
						// Valeur supérieure à zéro
						while (value > 0)
						{
							charBuffer[--index] = value % 10 + '0';
							nPositions--;
							value /= 10;
						}
					}

					// S'il reste des positions à remplir, alors faisons-le
					while (nPositions > 0)
						nPositions--, charBuffer[--index] = padChar;

					// Ajoute le signe moins
					if (bNegative)
						charBuffer[--index] = '-';

					// Ajoute l'entier converti à la chaîne finale
					while (charBuffer[index])
						*dest++ = charBuffer[index++];
					break;
				}

				// Hexadecimal (pointer for example)
				case 'x':
				{
					// Récupère un argument
					u32 value = va_arg(arg_ptr, u32);

					// Termine la chaîne et commence par la fin
					index = numberof(charBuffer) - 1;
					charBuffer[index] = 0;

					// Convertit l'entier en chaîne
					if (value == 0)
						charBuffer[--index] = '0', nPositions--;
					else
					{
						// Valeur supérieure à zéro
						while (value > 0)
						{
							if ((value & 15) < 10)
								charBuffer[--index] = (value & 15) + '0';
							else
								charBuffer[--index] = (value & 15) - 10 + 'a';
							nPositions--;
							value >>= 4;
						}
					}

					// S'il reste des positions à remplir, alors faisons-le
					while (nPositions > 0)
						nPositions--, charBuffer[--index] = padChar;

					// Ajoute l'entier converti à la chaîne finale
					while (charBuffer[index])
						*dest++ = charBuffer[index++];
					break;
				}
			}

			continue;
		}

		// Caractère normal => à insérer
		*dest++ = *format++;
	}

	// Termine la chaîne
	*dest = 0;
}

void formatString(char *dest, const char *format, ...)
{
	va_list arg_ptr;

	va_start(arg_ptr, format);
	vFormatString(dest, format, arg_ptr);
}

