/*---------------------------------------------------------------------------------
	$Id: console.c,v 1.20 2007/07/07 20:25:36 bigredpimp Exp $

	Copyright (C) 2005
		Michael Noland (joat)
		Jason Rogers (dovoto)
		Dave Murphy (WinterMute)

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/

#include <nds/jtypes.h>
#include <nds/memory.h>
#include "console11.h"
#include <nds/arm9/video.h>
#include <nds/arm9/background.h>
//#include <default_font_bin.h>
extern const u8 default_font_bin_end[];
extern const u8 default_font_bin[];
extern const u32 default_font_bin_size;

#include <stdio.h>
#include <stdarg.h>
#include <sys/iosupport.h>

//	global console variables

#define CONSOLE_WIDTH 32
#define CONSOLE_HEIGHT 24
#define TAB_SIZE 3

//	map to print to
static u16* debugfontMap;

//	location of cursor
static int debugrow, debugcol;
static int debugsavedX, debugsavedY;

//	font may not start on a character base boundry
static u16 debugfontOffset;

//	the first character in the set (0 if you have a full set)
static u16 debugfontStart;

//	the 16-color palette to use
bool debugfontBold = false;
static u16 debugfontPal;

static int debugconsoleInitialised = 0;

void debugconsolePrintChar(char c);


//---------------------------------------------------------------------------------
static void debugconsoleCls(char mode) {
//---------------------------------------------------------------------------------

	int i = 0;
	int colTemp,rowTemp;

	switch (mode)
	{
		case '0':
		{
			colTemp = debugcol;
			rowTemp = debugrow;

			while(i++ < ((CONSOLE_HEIGHT * CONSOLE_WIDTH) - (rowTemp * CONSOLE_WIDTH + colTemp))) debugconsolePrintChar(' ');

			debugcol = colTemp;
			debugrow = rowTemp;
			break;
		}	
		case '1':
		{
			colTemp = debugcol;
			rowTemp = debugrow;

			debugrow = 0;
			debugcol = 0;

			while (i++ < (rowTemp * CONSOLE_WIDTH + colTemp)) debugconsolePrintChar(' ');

			debugcol = colTemp;
			debugrow = rowTemp;
			break;
		}	
		case '2':
		{
			debugrow = 0;
			debugcol = 0;

			while(i++ < CONSOLE_HEIGHT * CONSOLE_WIDTH) debugconsolePrintChar(' ');

			debugrow = 0;
			debugcol = 0;
			break;
		}	
	}
}
//---------------------------------------------------------------------------------
static void debugconsoleClearLine(char mode) {
//---------------------------------------------------------------------------------

	int i = 0;
	int colTemp;

	switch (mode)
	{
		case '0':
		{
			colTemp = debugcol;

			while(i++ < (CONSOLE_WIDTH - colTemp)) {
				debugconsolePrintChar(' ');
			}

			debugcol = colTemp;

			break;
		}	
		case '1':
		{
			colTemp = debugcol;

			debugcol = 0;

			while(i++ < ((CONSOLE_WIDTH - colTemp)-2)) {
				debugconsolePrintChar(' ');
			}

			debugcol = colTemp;

			break;
		}	
		case '2':
		{
			colTemp = debugcol;

			debugcol = 0;

			while(i++ < CONSOLE_WIDTH) {
				debugconsolePrintChar(' ');
			}

			debugcol = colTemp;

			break;
		}
		default:
		{
			colTemp = debugcol;

			while(i++ < (CONSOLE_WIDTH - colTemp)) {
				debugconsolePrintChar(' ');
			}

			debugcol = colTemp;

			break;
		}
	}
}


void _consolePrintf(const char* format, ...)
{
  char strbuf[256];
  
  va_list args;
  
  va_start( args, format );
  vsnprintf( strbuf, 255, format, args );
  _consolePrint(strbuf);
}




//---------------------------------------------------------------------------------
int _consolePrint(const char *ptr) {
//---------------------------------------------------------------------------------

	if (!debugconsoleInitialised) return -1;

	char chr;

	int i, count = 0;
	char *tmp = (char*)ptr;

	if(!tmp ) return -1;

	i = 0;
	while(*tmp!='\0') {

		chr = *(tmp++);
		i++; count++;

		if ( chr == 0x1b && *tmp == '[' ) {
			bool escaping = true;
			char *escapeseq	= tmp;
			int escapelen = 0;

			do {
				chr = *(tmp++);
				i++; count++; escapelen++;
				int parameter;
				
				switch (chr) {
					/////////////////////////////////////////
					// Cursor directional movement
					/////////////////////////////////////////
					case 'A':
						siscanf(escapeseq,"[%dA", &parameter);
						debugrow =  (debugrow - parameter) < 0 ? 0 : debugrow - parameter;
						escaping = false;
						break;
					case 'B':
						siscanf(escapeseq,"[%dB", &parameter);
						debugrow =  (debugrow + parameter) > CONSOLE_HEIGHT - 1 ? CONSOLE_HEIGHT - 1 : debugrow + parameter;
						escaping = false;
						break;
					case 'C':
						siscanf(escapeseq,"[%dC", &parameter);
						debugcol =  (debugcol + parameter) > CONSOLE_WIDTH - 1 ? CONSOLE_WIDTH - 1 : debugcol + parameter;
						escaping = false;
						break;
					case 'D':
						siscanf(escapeseq,"[%dC", &parameter);
						debugcol =  (debugcol - parameter) < 0 ? 0 : debugcol - parameter;
						escaping = false;
						break;
					/////////////////////////////////////////
					// Cursor position movement
					/////////////////////////////////////////
					case 'H':
					case 'f':
						siscanf(escapeseq,"[%d;%df", &debugrow, &debugcol);
						escaping = false;
						break;
					/////////////////////////////////////////
					// Screen clear
					/////////////////////////////////////////
					case 'J':
						debugconsoleCls(escapeseq[escapelen-2]);
						escaping = false;
						break;
					/////////////////////////////////////////
					// Line clear
					/////////////////////////////////////////
					case 'K':
						debugconsoleClearLine(escapeseq[escapelen-2]);
						escaping = false;
						break;
					/////////////////////////////////////////
					// Save cursor position
					/////////////////////////////////////////
					case 's':
						debugsavedX = debugcol;
						debugsavedY = debugrow;
						escaping = false;
						break;
					/////////////////////////////////////////
					// Load cursor position
					/////////////////////////////////////////
					case 'u':
						debugcol = debugsavedX;
						debugrow = debugsavedY;
						escaping = false;
						break;
				}
			} while (escaping);
		continue;
		}

		debugconsolePrintChar(chr);
	}

	return count;
}


/*---------------------------------------------------------------------------------
	debugconsoleInit
	param:
		font: 16 color font
		charBase: the location the font data will be loaded to
		numCharacters: count of characters in the font
		charStart: The ascii number of the first character in the font set
					if you have a full set this will be zero
		map: pointer to the map you will be printing to.
		pal: specifies the 16 color palette to use, if > 15 it will change all non-zero
			entries in the font to use palette index 255
---------------------------------------------------------------------------------*/
void debugconsoleInit(	u16* font, u16* charBase,
					u16 numCharacters, u8 charStart,
					u16* map, u8 pal, u8 bitDepth) {
//---------------------------------------------------------------------------------
	int i;

	debugrow = debugcol = 0;

	debugfontStart = charStart;

	debugfontOffset = 0;

	debugfontMap = map;

	if(bitDepth == 16)
	{
		if(pal < 16)
		{
			debugfontPal = pal << 12;

			for (i = 0; i < numCharacters * 16; i++)
				charBase[i] = font[i];
		}
		else
		{
			debugfontPal = 15 << 12;

			for (i = 0; i < numCharacters * 16; i++)
			{
				u16 temp = 0;

				if(font[i] & 0xF)
					temp |= 0xF;
				if(font[i] & 0xF0)
					temp |= 0xF0;
				if(font[i] & 0xF00)
					temp |= 0xF00;
				if(font[i] & 0xF000)
					temp |= 0xF000;

				charBase[i] = temp;
			}
		}
	}//end if bitdepth
	else
	{
		debugfontPal = 0;
		for(i = 0; i < numCharacters * 16; i++)
		{
			u32 temp = 0;

			if(font[i] & 0xF)
				temp = 255;
			if(font[i] & 0xF0)
				temp |= 255 << 8;
			if(font[i] & 0xF00)
				temp |= 255 << 16;
			if(font[i] & 0xF000)
				temp |= 255 << 24;

			((u32*)charBase)[i] = temp;

		}
	}

	//devoptab_list[STD_OUT] = &dotab_stdout;
	//devoptab_list[STD_ERR] = &dotab_stdout;
	//setvbuf(stderr, NULL , _IONBF, 0);
	//setvbuf(stdout, NULL , _IONBF, 0);
	debugconsoleCls('2');
	debugconsoleInitialised = 1;

}

//---------------------------------------------------------------------------------
// Places the console in a default mode using bg0 of the sub display, and vram c for 
// font and map..this is provided for rapid prototyping and nothing more
void debugconsoleDemoInit(void) {
//---------------------------------------------------------------------------------
	videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);	//sub bg 0 will be used to print text
	vramSetBankC(VRAM_C_SUB_BG); 

	SUB_BG0_CR = BG_MAP_BASE(31);

	BG_PALETTE_SUB[255] = RGB15(31,31,31);	//by default font will be rendered with color 255

	//debugconsoleInit() is a lot more flexible but this gets you up and running quick
	debugconsoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
}

//---------------------------------------------------------------------------------
void debugconsoleInitDefault(u16* map, u16* charBase, u8 bitDepth) {
//---------------------------------------------------------------------------------
	debugconsoleInit((u16*)default_font_bin, charBase, 256, 0, map, CONSOLE_USE_COLOR255, bitDepth);
}

//void consoleInitColorDefault(u16* map, u16* charBase) {
//	debugconsoleInit((u16*)default_font_bin, charBase, 256, 0, map, CONSOLE_USE_COLOR255, bitDepth);
//}

//---------------------------------------------------------------------------------
static void debugnewRow() {
//---------------------------------------------------------------------------------
	int i;
	debugrow++;
	if(debugrow >= CONSOLE_HEIGHT) {
		debugrow--;

		for(i = CONSOLE_WIDTH; i < CONSOLE_HEIGHT * CONSOLE_WIDTH; i++) debugfontMap[i - CONSOLE_WIDTH] = debugfontMap[i];

		for(i = 0; i < CONSOLE_WIDTH; i++) debugfontMap[i + (CONSOLE_HEIGHT-1)*CONSOLE_WIDTH] = debugfontPal | (u16)(' ' + debugfontOffset - debugfontStart);

	}
}


//---------------------------------------------------------------------------------
void debugconsolePrintChar(char c) {
//---------------------------------------------------------------------------------

	if(debugcol >= CONSOLE_WIDTH) {
		debugcol = 0;

		debugnewRow();
	}

	switch(c) {
		/*
			The only special characters we will handle are tab (\t), carriage return (\r) & line feed (\n).
			Carriage return & line feed will function the same: go to next line and put cursor at the beginning.
			For everything else, use VT sequences.
			
			Reason: VT sequences are more specific to the task of cursor placement.
			The special escape sequences \b \f & \v are archaic and non-portable.
		*/
		case 9:
			debugcol += TAB_SIZE;
			break;
		case 10:
		case 13:
			debugnewRow();
			debugcol = 0;
			break;
		default:
			debugfontMap[debugcol + debugrow * CONSOLE_WIDTH] = debugfontPal | (u16)(c + debugfontOffset - debugfontStart);
			++debugcol;
			break;
	}
}

//---------------------------------------------------------------------------------
void debugconsoleClear(void) {
//---------------------------------------------------------------------------------
	_consolePrint("\x1b[2J");
}


