#include "wl_def.h"

#include "SDL.h"

byte *gfxbuf = NULL;
SDL_Surface *surface;
SDL_Joystick *joy;

extern void keyboard_handler(int code, int press);
extern boolean InternalKeyboard[NumCodes];

int main (int argc, char *argv[])
{
	return WolfMain(argc, argv);
}

void DisplayTextSplash(byte *text);

/*
==========================
=
= Quit
=
==========================
*/

void Quit(char *error)
{
	memptr screen = NULL;

	if (!error || !*error) {
		CA_CacheGrChunk(ORDERSCREEN);
		screen = grsegs[ORDERSCREEN];
		WriteConfig();
	} else if (error) {
		CA_CacheGrChunk(ERRORSCREEN);
		screen = grsegs[ERRORSCREEN];
	}
	
	ShutdownId();
	
	if (screen) {
		//DisplayTextSplash(screen);
	}
	
	if (error && *error) {
		fprintf(stderr, "Quit: %s\n", error);
		exit(EXIT_FAILURE);
 	}
	exit(EXIT_SUCCESS);
}

void VL_WaitVBL(int vbls)
{
	long last = get_TimeCount() + vbls;
	while (last > get_TimeCount()) ;
}

void VW_UpdateScreen()
{
	//VL_WaitVBL(1); 
	//memcpy(surface->pixels, gfxbuf, vstride*vheight);
	//SDL_UpdateRect(surface, 0, 0, 0, 0);
	
	SDL_Flip(surface);
}

/*
=======================
=
= VL_Startup
=
=======================
*/

void VL_Startup()
{
	vwidth = 320;
	vstride = 320;
	vheight = 200;
	vwidth = 480;
	vstride = 480;
	vheight = 272;

	if (MS_CheckParm("x2")) {
		vwidth *= 2;
		vstride *= 2;
		vheight *= 2;
	} else if (MS_CheckParm("x3")) {
		vwidth *= 3;
		vstride *= 3;
		vheight *= 3;
	}
	
	//if (gfxbuf == NULL) 
	//	gfxbuf = malloc(vwidth * vheight * 1);
/* TODO: renable parachute for release version? */		
	if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK|SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE) < 0) {
		Quit("Couldn't init SDL");
	}

	if (MS_CheckParm("fullscreen"))
		//surface = SDL_SetVideoMode(vwidth, vheight, 8, SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
		surface = SDL_SetVideoMode(vwidth, vheight, 8, SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN|SDL_DOUBLEBUF);
	else
		//surface = SDL_SetVideoMode(vwidth, vheight, 8, SDL_SWSURFACE|SDL_HWPALETTE);
		surface = SDL_SetVideoMode(vwidth, vheight, 8, SDL_HWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF);
		
	if (surface == NULL) {
		SDL_Quit();
		Quit("Couldn't set 320x200 mode");
	}
	gfxbuf = surface->pixels;
	vstride=surface->pitch;
	
	if (surface->flags & SDL_FULLSCREEN)
		SDL_ShowCursor(0);
	
	SDL_WM_SetCaption(GAMENAME, GAMENAME);	

	if(SDL_NumJoysticks()>0)
		joy=SDL_JoystickOpen(0);
}

/*
=======================
=
= VL_Shutdown
=
=======================
*/

void VL_Shutdown()
{
	//if (gfxbuf != NULL) {
	//	free(gfxbuf);
	//	gfxbuf = NULL;
	//}
	SDL_Quit();
}

/* ======================================================================== */

/*
=================
=
= VL_SetPalette
=
=================
*/

void VL_SetPalette(const byte *palette)
{
	SDL_Color colors[256];
	int i;
	
	VL_WaitVBL(1);
	
	for (i = 0; i < 256; i++)
	{
		colors[i].r = palette[i*3+0] << 2;
		colors[i].g = palette[i*3+1] << 2;
		colors[i].b = palette[i*3+2] << 2;
	}
	SDL_SetColors(surface, colors, 0, 256);
	// Should also do a flip here.
	SDL_Flip(surface);
}

/*
=================
=
= VL_GetPalette
=
=================
*/

void VL_GetPalette(byte *palette)
{
	int i;
	for (i=0;i<256;i++)
	{
		palette[i*3+0] = surface->format->palette->colors[i].r >> 2;
		palette[i*3+1] = surface->format->palette->colors[i].g >> 2;
		palette[i*3+2] = surface->format->palette->colors[i].b >> 2;
	}
}

static int XKeysymToScancode(unsigned int keysym)
{
	switch (keysym) {
		case SDLK_KP_ENTER:
		case SDLK_RETURN:
			return sc_Enter;
		case SDLK_ESCAPE:
			return sc_Escape;
		case SDLK_SPACE:
			return sc_Space;
		case SDLK_BACKSPACE:
			return sc_BackSpace;
		case SDLK_TAB:
			return sc_Tab;
		case SDLK_LALT:
			return sc_Alt;
		case SDLK_LCTRL:
			return sc_Control;
		case SDLK_CAPSLOCK:
			return sc_CapsLock;
		case SDLK_LSHIFT:
			return sc_LShift;
		case SDLK_RSHIFT:
			return sc_RShift;
		
		case SDLK_UP:
		case SDLK_KP8:
			return sc_UpArrow;
		case SDLK_DOWN:
		case SDLK_KP2:
			return sc_DownArrow;
		case SDLK_LEFT:
		case SDLK_KP4:
			return sc_LeftArrow;
		case SDLK_RIGHT:
		case SDLK_KP6:
			return sc_RightArrow;
		case SDLK_HOME:
			return sc_Home;
		case SDLK_END:
			return sc_End;
		case SDLK_PAGEUP:
			return sc_PgUp;
		case SDLK_PAGEDOWN:
			return sc_PgDn;
			
		case SDLK_INSERT:
			return sc_Insert;
		case SDLK_DELETE:
			return sc_Delete;
		case SDLK_F1:
			return sc_F1;
		case SDLK_F2:
			return sc_F2;
		case SDLK_F3:
			return sc_F3;
		case SDLK_F4:
			return sc_F4;
		case SDLK_F5:
			return sc_F5;
		case SDLK_F6:
			return sc_F6;
		case SDLK_F7:
			return sc_F7;
		case SDLK_F8:
			return sc_F8;
		case SDLK_F9:
			return sc_F9;
		case SDLK_F10:
			return sc_F10;
		case SDLK_F11:
			return sc_F11;
		case SDLK_F12:
			return sc_F12;	
		
		case SDLK_1:
			return sc_1;
		case SDLK_2:
			return sc_2;
		case SDLK_3:
			return sc_3;
		case SDLK_4:
			return sc_4;
		case SDLK_5:
			return sc_5;
		case SDLK_6:
			return sc_6;
		case SDLK_7:
			return sc_7;
		case SDLK_8:
			return sc_8;
		case SDLK_9:
			return sc_9;
		case SDLK_0:
			return sc_0;
		
		case SDLK_a:
			return sc_A;
		case SDLK_b:
			return sc_B;
		case SDLK_c:
			return sc_C;
		case SDLK_d:
			return sc_D;
		case SDLK_e:
			return sc_E;
		case SDLK_f:
			return sc_F;
		case SDLK_g:
			return sc_G;
		case SDLK_h:
			return sc_H;
		case SDLK_i:
			return sc_I;
		case SDLK_j:
			return sc_J;
		case SDLK_k:
			return sc_K;
		case SDLK_l:
			return sc_L;
		case SDLK_m:
			return sc_M;
		case SDLK_n:
			return sc_N;
		case SDLK_o:
			return sc_O;
		case SDLK_p:
			return sc_P;
		case SDLK_q:
			return sc_Q;
		case SDLK_r:
			return sc_R;
		case SDLK_s:
			return sc_S;
		case SDLK_t:
			return sc_T;
		case SDLK_u:
			return sc_U;
		case SDLK_v:
			return sc_V;
		case SDLK_w:
			return sc_W;
		case SDLK_x:
			return sc_X;
		case SDLK_y:
			return sc_Y;
		case SDLK_z:
			return sc_Z;
		
		case SDLK_PAUSE:
			return 0xE1;
		default:
			return sc_None;
	}
}

static int JoybuttonToScancode(unsigned int keysym)
{
	switch (keysym) {
		case 11: // Start
			return sc_Enter;
		case 10: // Select
			return sc_Escape;
		case 0:	// Triangle
			return sc_Space;
		case 3: // Square
			return sc_BackSpace;
		case 2: // Cross
			return sc_Control;
		
		case 8:	// up
			return sc_UpArrow;
		case 6: // down
			return sc_DownArrow;
		case 7: // left
			return sc_LeftArrow;
		case 9: // right
			return sc_RightArrow;
			
		case 1: // circle
			return sc_Y;
		
		case 4:
			return sc_RShift;
		case 5:
			return sc_Alt;
		case 13:	// Hold?
			return 0xE1;
		default:
			return sc_None;
	}
}

void INL_Update()
{
	SDL_Event event;
	boolean DebouncedKeyboard[NumCodes];
	
	memcpy(DebouncedKeyboard, InternalKeyboard, sizeof(DebouncedKeyboard));
		
	if (SDL_PollEvent(&event)) {
		do {
			switch(event.type) {
				case SDL_KEYDOWN:
					keyboard_handler(XKeysymToScancode(event.key.keysym.sym), 1);
					break;
				case SDL_KEYUP:
					keyboard_handler(XKeysymToScancode(event.key.keysym.sym), 0);
					break;
				case SDL_JOYBUTTONDOWN:
					keyboard_handler(JoybuttonToScancode(event.jbutton.button), 1);
					break;
				case SDL_JOYBUTTONUP:
					keyboard_handler(JoybuttonToScancode(event.jbutton.button), 0);
					break;
				default:
					break;
			}
		} while (SDL_PollEvent(&event));
	}
	
	if (InternalKeyboard[sc_Alt] && 
	(!DebouncedKeyboard[sc_Return] && InternalKeyboard[sc_Return])) {
		SDL_GrabMode gm;
		
		SDL_WM_ToggleFullScreen(surface);
		
		gm = SDL_WM_GrabInput(SDL_GRAB_QUERY);
		if (gm == SDL_GRAB_OFF && !(surface->flags & SDL_FULLSCREEN))
			SDL_ShowCursor(1);
		else
			SDL_ShowCursor(0);
	}
	
	if (InternalKeyboard[sc_Control] &&
	(!DebouncedKeyboard[sc_G] && InternalKeyboard[sc_G])) {
		SDL_GrabMode gm;
		
		gm = SDL_WM_GrabInput(SDL_GRAB_QUERY);
		SDL_WM_GrabInput((gm == SDL_GRAB_ON) ? SDL_GRAB_OFF : SDL_GRAB_ON);
		
		gm = SDL_WM_GrabInput(SDL_GRAB_QUERY);
		if (gm == SDL_GRAB_OFF && !(surface->flags & SDL_FULLSCREEN))
			SDL_ShowCursor(1);
		else
			SDL_ShowCursor(0);
	}
	
	/* ctrl-z for iconify window? */
}

void IN_GetMouseDelta(int *dx, int *dy)
{
	int x, y;
	
	SDL_GetRelativeMouseState(&x, &y);
	
	if (dx)
		*dx = x;
	if (dy)
		*dy = y;
}

byte IN_MouseButtons()
{
	return SDL_GetMouseState(NULL, NULL);
}
