#include <nitro.h>

#include "gui.h"
#include "../../../include/gflib/strcode.h"
#include "../../../include/pm_version.h"

// localize_spec_mark(LANG_ALL) yamamoto 2007/02/27
#if PM_LANG == LANG_ENGLISH
#include "msg_eng.h"
#elif PM_LANG == LANG_FRANCE
#include "msg_fra.h"
#elif PM_LANG == LANG_GERMANY
#include "msg_ger.h"
#elif PM_LANG == LANG_ITALY
#include "msg_ita.h"
#elif PM_LANG == LANG_SPAIN
#include "msg_spa.h"
#elif PM_LANG == LANG_KOREA
#include "msg_kor.h"
#endif

#define	GX_DMA_NUMBER	1

extern const u8 _binary_font_system_gly[];
extern const u8 _binary_font_system_wid[];
extern const u8 _binary_winframe_system_bg[];
extern const u8 _binary_winframe_system_pal[];
extern const u8 _binary_winframe_talk_bg[];
extern const u8 _binary_winframe_talk_pal[];
extern const u8 _binary_win_cursor1_bg[];
extern const u8 _binary_wireless_strength_level_w_bg[];
extern const u8 _binary_wireless_strength_level_w_pal[];

void FntDataColorSet(u8 col_f, u8 col_b, u8 col_s);
void FntDataColorBackUp(u8* col_f, u8* col_b, u8* col_s);
void FntDataColorRecover(u8* col_f, u8* col_b, u8* col_s);
void FntDataSet8x8_2bit(u32 radrs,u32 wadrs);
u8 FntDataColorGet(u8 mode);

void guiInit(void)
{
	GX_InitEx(GX_DMA_NUMBER);
// localize_spec_mark(LANG_ALL) yamamoto 2007/02/13
// ちらつき防止。
	GX_DispOff();
	GXS_DispOff();

	GX_SetMasterBrightness(-16);
	GXS_SetMasterBrightness(-16);

	// 表示設定初期化
	GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);

	MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
	(void)GX_DisableBankForLCDC();
	MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
	MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
	MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
	MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);

	// 文字列表示用に2D表示設定
	GX_SetBankForBG(GX_VRAM_BG_128_A);

	// BG0 文字 SCR 2k CHR 24k 使用
	G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
					 GX_BG_SCRBASE_0x6000,
					 GX_BG_CHARBASE_0x00000,    // CHR ベースブロック 0
					 GX_BG_EXTPLTT_01);
	G2_SetBG0Priority(0);
	G2_BG0Mosaic(FALSE);
	// BG1 ウィンドウ SCR 2k BG 1k 使用
	G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
					 GX_BG_SCRBASE_0x7000,
					 GX_BG_CHARBASE_0x08000,    // CHR ベースブロック 8000
					 GX_BG_EXTPLTT_01);
	G2_SetBG1Priority(1);
	G2_BG1Mosaic(FALSE);

	GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);

	GX_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_BG1);
	GX_LoadBG1Char(_binary_winframe_system_bg, 32, 32 * 9);
	GX_LoadBG1Char(_binary_winframe_talk_bg, 32 * 10, 32 * 18);
	GX_LoadBG1Char(_binary_wireless_strength_level_w_bg, 32 * 28, 32 * 16);
	GX_LoadBGPltt(_binary_winframe_system_pal, 32, 32);
	GX_LoadBGPltt(_binary_winframe_talk_pal, 64, 32);
	GX_LoadBGPltt(_binary_wireless_strength_level_w_pal, 96, 32);

	((u16 *)HW_BG_PLTT)[0] = 0;
	((u16 *)HW_BG_PLTT)[1] = 0x7fff;
	((u16 *)HW_BG_PLTT)[2] = 0x2d6a;
	((u16 *)HW_BG_PLTT)[3] = 0x2d6a; // 文字
	((u16 *)HW_BG_PLTT)[4] = 0x62f5; // 影
	FntDataColorSet(3, 0, 4);
	{
		u16 *s;
		int i;

		s = (u16 *)G2_GetBG0ScrPtr();
		for (i = 0; i < 32 * 24; i++) {
			s[i] = (u16)i;
		}
		s = (u16 *)G2_GetBG1ScrPtr();
		for (i = 0; i < 32 * 24; i++) {
			s[i] = 0;
		}
	}
	// 副画面表示しない
	GXS_SetVisiblePlane(GX_PLANEMASK_NONE);
	((u16 *)HW_BG_PLTT)[0] = 0;
}

void winframeDraw(int type)
{
	u16 *s = (u16 *)G2_GetBG1ScrPtr();
	int ys; // talkのy方向のサイズ
	int i, j;

	if (type == 1) {
		ys = 12;
	} else {
		ys = 6;
	}
	for (i = 32 * 2; i < 32 * (24 - ys); i++) {
		s[i] = 0;
	}
	if (type == 2) {
		for (i = 0; i < 6; i++) {
			int v;
			if (i == 0) {
				v = 0;
			} else if (i < ys - 1) {
				v = 1;
			} else {
				v = 2;
			}
			for (j = 0; j < 8; j++) {
				int u;
				if (j == 0) {
					u = 0;
				} else if (j < 7) {
					u = 1;
				} else {
					u = 2;
				}
				s[32 * (12 + i) + 24 + j] = (u16)(0x1000 + 1 + 3 * v + u);
			}
		}
	}
	for (i = 0; i < ys; i++) {
		int v;
		if (i == 0) {
			v = 0;
		} else if (i < ys - 1) {
			v = 1;
		} else {
			v = 2;
		}
		for (j = 0; j < 32; j++) {
			int u;
			if (j < 2) {
				u = j;
			} else if (j < 29) {
				u = 2;
			} else {
				u = 3 + (j - 29);
			}
			s[32 * (24 - ys + i) + j] = (u16)(0x2000 + 10 + 6 * v + u);
		}
	}
}

static void drawChar(int x, int y, const u8 *gly)
{
	u16 bmp[64];
	int i, o0, o1, o2, o3, o4, b;

	FntDataSet8x8_2bit((u32)gly, (u32)bmp);
	FntDataSet8x8_2bit((u32)(gly + 16), (u32)(bmp + 32));
	FntDataSet8x8_2bit((u32)(gly + 32), (u32)(bmp + 16));
	FntDataSet8x8_2bit((u32)(gly + 48), (u32)(bmp + 48));
	// u16単位で2進法でアドレスを書くと、YYYYYXXXXXyyyx となる。
	o0 = x << 1 & 0x1f0 | x >> 2 & 1;
	o1 = x + 4 << 1 & 0x1f0 | x + 4 >> 2 & 1;
	o2 = x + 8 << 1 & 0x1f0 | x + 8 >> 2 & 1;
	o3 = x + 12 << 1 & 0x1f0 | x + 12 >> 2 & 1;
	o4 = x + 16 << 1 & 0x1f0 | x + 16 >> 2 & 1;
	b = x % 4 << 2;
	for (i = 0; i < 16; i++) {
		u16 *s = (u16 *)G2_GetBG0CharPtr()
			+ (y + i >> 3 << 9 | y + i << 1 & 0xe);
		s[o0] |= bmp[i + i] << b;
		s[o1] = (u16)(((u32)bmp[i + i + 1] << 16 | bmp[i + i]) >> 16 - b);
		s[o2] = (u16)(((u32)bmp[i + i + 32] << 16 | bmp[i + i + 1]) >> 16 - b);
		s[o3] = (u16)(((u32)bmp[i + i + 33] << 16 | bmp[i + i + 32]) >> 16 - b);
		s[o4] = (u16)((u32)bmp[i + i + 33] >> 16 - b);
	}
}

void fontClear()
{
	MI_CpuClear16(G2_GetBG0CharPtr(), 32 * 32 * 24);
}

void fontDraw(int type, int x, int y, const u16 *str)
{
	// localize_spec_mark(LANG_KOREA) yamamoto 2007/11/26
	// フォント幅情報の構造が変わったため。
#define	WIDTH_PROPOTIONAL		(-1)
	typedef struct {
		u16 maxCode;			// 2 bytes
		union {					// 2 bytes
			u16 dataType;		// ピクセルテーブルでは圧縮形式を格納
			s16 width;			// 幅テーブルではピクセル幅を格納（-1ならプロポーショナル）
		};
		u32 dataOffset;			// 4 bytes
	} FONT_AREA;				// 8 bytes
	FONT_AREA *font_area;
	u32 font_area_num;
	int min_code;
	const u8 *gly;
	const u8 *wid;
	int xs = x;

	(void)type;
	gly = _binary_font_system_gly;
	wid = _binary_font_system_wid;
	font_area_num = *(u32 *)_binary_font_system_wid;
	while (*str != EOM_) {
		// localize_spec_mark(LANG_ALL) yamamoto 2007/02/10
		// 改行コードで複数行描画できるようにした。
		// 本当は翻訳のことを考えると送り文字も含めて１つのメッセージに
		// したかったが、ローカライズでプログラムの流れを変えるような変更は
		// 怖いためやめておく。
		// また、メッセージデータだけ切り出した方がコンバータの都合がよいのだが、
		// 現在ローカル自動変数としてスタックに積まれているので、そのメモリ構造を
		// 変えるのも、やはり怖いのでやめておく。
		if (*str != CR_CODE_) {
			int		i;

			drawChar(x, y, gly + 64 * (*str - 1));
			min_code = 0;
			font_area = (FONT_AREA *)(_binary_font_system_wid + sizeof(u32));
			for (i = 0; i < font_area_num; ++i) {
				if (*str < font_area->maxCode) {
					if (font_area->width == WIDTH_PROPOTIONAL) {
						x += wid[font_area->dataOffset + (*str - 1) - min_code];
					} else {
						x += (u8)font_area->width;
					}
					break;
				}
				min_code = font_area->maxCode;
				font_area++;
			}
		} else {
			x = xs;
			y += 16;
		}
		str++;
	}
}

void drawCursor(int count)
{
	const u16 *p = (const u16 *)(_binary_win_cursor1_bg + 128 * count);
	int       i, j;

	for (i = 0; i < 2; i ++) {
		u16 *c = (u16 *)G2_GetBG0CharPtr() + 16 * (32 * (21 + i) + 29);
		for (j = 0; j < 8; j++) {
			c[2 * j + 1] = p[32 * i + 2 * j];
			c[2 * j + 16] = p[32 * i + 2 * j + 1];
			c[2 * j + 17] = p[32 * i + 2 * j + 16];
			c[2 * j + 32] = p[32 * i + 2 * j + 17];
		}
	}
}

void drawYesNo(int no)
{
	const u16 cursor[] = {cursor_, EOM_};
	const u16 str1[] = { DOWNLOADER_001 };
	const u16 str2[] = { DOWNLOADER_002 };
	int       i;

	for (i = 12; i < 18; i++) {
		MI_CpuClear16((u8 *)G2_GetBG0CharPtr() + 32 * (32 * i + 25), 32);
	}
	if (no == 0) {
		fontDraw(0, 200, 104, cursor);
	} else {
		fontDraw(0, 200, 120, cursor);
	}
	fontDraw(0, 208, 104, str1);
	fontDraw(0, 208, 120, str2);
}

void drawLevel(int level)
{
	u16 *s;

	s = (u16 *)G2_GetBG1ScrPtr();
	if (level < 0) {
		s[0x1e] = 0;
		s[0x1f] = 0;
		s[0x3e] = 0;
		s[0x3f] = 0;
	} else {
		s[0x1e] = (u16)(0x3000 + 28 + 4 * level);
		s[0x1f] = (u16)(0x3000 + 29 + 4 * level);
		s[0x3e] = (u16)(0x3000 + 30 + 4 * level);
		s[0x3f] = (u16)(0x3000 + 31 + 4 * level);
	}
}

// msg_printからフォント描画部分を抜き出したもの
enum COLOR_GET_MODE {
	COLOR_F,
	COLOR_S,
	COLOR_B
};
//---------------------------------------------------------------------------------------------
/*
 *	FntDataSet8x8_2bit を呼ぶ前に、色番号をセットしておく（高速化のため）
 *
 * @param	col_f	文字色番号
 * @param	col_b	背景色番号
 * @param	col_s	影色番号
 */
//---------------------------------------------------------------------------------------------
#define DOTTBL_USE

#ifdef DOTTBL_USE
static u16 DotTbl[256];
#else
static u16 Col_b4, Col_b8, Col_b12;
static u16 Col_f4, Col_f8, Col_f12;
static u16 Col_s4, Col_s8, Col_s12;
#endif
static u16 Col_b, Col_f, Col_s;

void FntDataColorSet(u8 col_f, u8 col_b, u8 col_s)
{
#ifdef DOTTBL_USE
	int d1,d2,d3,d4,n;
	u32 col[4];

	col[0] = 0;
	col[1] = col_f;
	col[2] = col_s;
	col[3] = col_b;

	Col_b = col_b;
	Col_f = col_f;
	Col_s = col_s;

	n = 0;
	for(d1=0; d1<4; d1++){
		for(d2=0; d2<4; d2++){
			for(d3=0; d3<4; d3++){
				for(d4=0; d4<4; d4++){
					DotTbl[n++] =	(u16)((col[d4]<<12) | 
									(col[d3]<<8) |
									(col[d2]<<4) |
									(col[d1]));
				}
			}
		}
	}

#else
	Col_b = col_b;
	Col_f = col_f;
	Col_s = col_s;

	Col_b4 = col_b << 4;
	Col_b8 = col_b << 8;
	Col_b12 = col_b << 12;

	Col_f4 = col_f << 4;
	Col_f8 = col_f << 8;
	Col_f12 = col_f << 12;

	Col_s4 = col_s << 4;
	Col_s8 = col_s << 8;
	Col_s12 = col_s << 12;
#endif
}

void FntDataColorBackUp(u8* col_f, u8* col_b, u8* col_s)
{
	*col_b = (u8)Col_b; 
	*col_f = (u8)Col_f;
	*col_s = (u8)Col_s;
}

void FntDataColorRecover(u8* col_f, u8* col_b, u8* col_s)
{
	FntDataColorSet(*col_f,*col_b,*col_s);
}

//---------------------------------------------------------------------------------------------
/*
 *	文字データ設定
 *
 * @param	radrs		読み込みデータ開始アドレス
 * @param	wadrs		書き込みデータバッファアドレス
 *
 * @retval	x_size		文字Ｘサイズ(文字詰め用)
 */
//---------------------------------------------------------------------------------------------
void FntDataSet8x8_2bit(u32 radrs,u32 wadrs)
{
	u32 dat;
	u16 *src;
	u16 *dst;

	src = (u16*)radrs;
	dst = (u16*)wadrs;


	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src++) << 24) >> 24;
	*dst++ = DotTbl[ dat ];

	dat = (u32)(*src) >> 8;
	*dst++ = DotTbl[ dat ];
	dat = (u32)((*src) << 24) >> 24;
	*dst = DotTbl[ dat ];

}
//---------------------------------------------------------------------------------------------
/*
 *	FntDataColorSet で設定した色番号を取得
 *
 * @param	mode	モード（enum COLOR_GET_MODE : msg_print.h）
 *
 * @retval	色番号
 */
//---------------------------------------------------------------------------------------------
u8 FntDataColorGet(u8 mode)
{
	switch(mode){
	case  COLOR_F: return (u8)Col_f;
	case  COLOR_B: return (u8)Col_b;
	case  COLOR_S: return (u8)Col_s;
	}
	return 0;
}

