// BlinkenSisters - Hunt for the Lost Pixels
//     Bringing back the fun of the 80s
//
// (C) 2005-07 Rene Schickbauer, Wolfgang Dautermann
//
// See License.txt for licensing information
//


#include "errorhandler.h"
#include "fonthandler.h"
#include "drawprimitives.h"
#include "sound.h"
#include <stdio.h>
#include <string.h>

#ifndef __OGGPLAYER
#include "lua.h"
#include "bl_lua.h"
#endif // __OGGPLAYER
#include "bsscreen.h"

#define PARSE_ERRORCODES
char* getErrorText(Uint32 errorcode) {
	static char intErrString[255];
	intErrString[0] = 0;
#define XX(errenum, errcode, errtxt) \
	if(errorcode == errcode) { \
		sprintf(intErrString, "%s", errtxt); \
	}
#include "errorcodes.h"
	return intErrString;
}
#undef PARSE_ERRORCODES

bool displayGraphicalErrors = false;

void dieWithError(Uint32 errorcode, const char* extrainfo, Uint32 linenum, const char* filename) {
	fprintf(stderr, "__          ___                           _ _ \n");
	fprintf(stderr, "\\ \\        / / |                         | | |\n");
	fprintf(stderr, " \\ \\  /\\  / /| |__   ___   ___  _ __  ___| | |\n");
	fprintf(stderr, "  \\ \\/  \\/ / | '_ \\ / _ \\ / _ \\| '_ \\/ __| | |\n");
	fprintf(stderr, "   \\  /\\  /  | | | | (_) | (_) | |_) \\__ \\_|_|\n");
	fprintf(stderr, "    \\/  \\/   |_| |_|\\___/ \\___/| .__/|___(_|_)\n");
	fprintf(stderr, "                               | |            \n");
	fprintf(stderr, "                               |_|            \n");
	fprintf(stderr, "\n");
	fprintf(stderr, "The Blinkensisters team is proud to present you the following fatal error:\n");
	fprintf(stderr, "Error %d: %s\nError-Info: %s\nError at %s:%d\n",
						errorcode, getErrorText(errorcode), extrainfo, filename, linenum);
#ifndef __OGGPLAYER
    if(doLuaStackTrace) {
        blLuaPrintBackTrace(doLuaStackTrace);
    }
#endif // __OGGPLAYER

	fprintf(stderr, "\nPlease report this error to cavac@users.sourceforge.net!\n");

	deInitSound(); // Stop all sound!
	if(displayGraphicalErrors) {
		displayErrorOnScreen(errorcode, extrainfo, linenum, filename);
	}

	exit(errorcode);
}

void displayErrorOnScreen(Uint32 errorcode, const char* extrainfo, Uint32 linenum, const char* filename) {

	/* Create a 32-bit surface with the bytes of each pixel in R,G,B,A order,
	as expected by OpenGL for textures */
	Uint32 rmask, gmask, bmask, amask;

	if(enableColor3D) {
		BS_Set3DMode(COLOR3D_NONE);
	}

	/* SDL interprets each pixel as a 32-bit number, so our masks must depend
	on the endianness (byte order) of the machine */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	rmask = 0xff000000;
	gmask = 0x00ff0000;
	bmask = 0x0000ff00;
	amask = 0x000000ff;
#else
	rmask = 0x000000ff;
	gmask = 0x0000ff00;
	bmask = 0x00ff0000;
	amask = 0xff000000;
#endif

	SDL_Surface* temp = SDL_CreateRGBSurface(SDL_SWSURFACE, SCR_WIDTH, SCR_HEIGHT, 32, rmask, gmask, bmask, amask);
	SDL_Surface* screenbackup = SDL_DisplayFormat(temp);
	SDL_FreeSurface(temp);

	SDL_Rect src, dest;
	dest.x = dest.y = src.x = src.y = 0;
	src.w = dest.w = SCR_WIDTH;
	src.h = dest.h = SCR_HEIGHT;

	// "Backup" screen to buffer
	SDL_BlitSurface(gScreen, &src, screenbackup, &dest);

	// a little showeffect
	for(Uint32 j = 0; j <= 5; j++) {
		drawrect((j + 1) * 50, 50, 20, 70, 0xff0000);
		drawrect((j + 1) * 50, 130, 20, 20, 0xff0000);
		BS_Flip(gScreen);
		SDL_Delay(250);
	}
	// Message
	char tmpstring[1000];
	sprintf(tmpstring, "Tentacle Meditation\n \nError %d: %s\n   at  %s:%d\n"
                           "Extra Info: \n %s\n \n   Press Escape to quit",
                           errorcode, getErrorText(errorcode), filename, linenum, extrainfo);

	/* number of lines in the errormessage */
	int z = 1;
	char *ch = strchr(tmpstring, '\n');
	while (ch) { ch = strchr(ch+1, '\n'); z++; } ;

	Uint32 errorheight = 20 // Border
			     + z * TTF_FontLineSkip(FONT_errorfont_12) ; // additional lines

	SDL_Color message_ERROR     = { 0xFF, 0x00, 0x00, 0 };

	bool keepDisplaying = true;
	bool blinkon = true;
	dest.y = errorheight;
	src.h = dest.h = SCR_HEIGHT - errorheight;
	while(keepDisplaying) {
		// copy the upper part of the original screen to the lower part of the error message
		SDL_BlitSurface(screenbackup, &src, gScreen, &dest);

		// Draw rectangle for message
		drawrect(0, 0, SCR_WIDTH, errorheight, 0x000000);
		if(blinkon) {
			drawrect(0, 0, SCR_WIDTH, 5, 0xFF0000);
			drawrect(0, errorheight - 5, SCR_WIDTH, 5, 0xFF0000);
			drawrect(0, 0, 5, errorheight, 0xFF0000);
			drawrect(SCR_WIDTH - 5, 0, 5, errorheight, 0xFF0000);
		}

		renderFontHandlerText(10, 10, tmpstring, message_ERROR, false, false, FONT_errorfont_12);

		BS_Flip(gScreen);
		SDL_Delay(500);
		blinkon = !blinkon;


		// Handle Keyboard
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				case SDL_KEYUP:
                    if (event.key.keysym.sym == SDLK_ESCAPE) {
						keepDisplaying = false;
						exit(0);
					}

					break;
			}
		}
	}
	return;
}


/* Display a full-screen INFO, WARNING or ERROR message for some time */
void displaymessage(int messagetype, const char *message, Uint32 delay_ms) {
	SDL_Color message_INFO      = { 0X22, 0x8B, 0x22, 0 };
	SDL_Color message_WARNING   = { 0xFF, 0x7F, 0x00, 0 };
	SDL_Color message_ERROR     = { 0xEE, 0x00, 0x00, 0 };

	if(enableColor3D) {
		BS_Set3DMode(COLOR3D_NONE);
	}

	SDL_FillRect(gScreen, NULL, 0xffffffff); /* Fill screen with white color */

	switch (messagetype) {
		case displaymessage_INFO:
			renderFontHandlerText(10, 100, "Information", message_INFO, true, false, FONT_menufont_50);
			renderFontHandlerText(10, 200, message, message_INFO, true, false, FONT_textfont_20);
			break;
		case displaymessage_WARNING:
			renderFontHandlerText(10, 100, "Warning", message_WARNING, true, false, FONT_menufont_50);
			renderFontHandlerText(10, 200, message, message_WARNING, true, false, FONT_textfont_20);
			break;
		case displaymessage_ERROR:
			renderFontHandlerText(10, 100, "Information", message_ERROR, true, false, FONT_menufont_50);
			renderFontHandlerText(10, 200, message, message_ERROR, true, false, FONT_textfont_20);
			break;
	}

	BS_Flip(gScreen);
	SDL_Delay(delay_ms);
}
