/* yields
	cat_init();
	cat_create_window();
	cat_pixel();
	cat_fill();
	cat_render();
	cat_play_wav();
	cat_stop_audio();
	cat_get_event();
*/

#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>

enum cat_events
{
	QUIT,
	KEYDOWN,
	KEYUP,
	MOUSEMOVE,
	MOUSEDOWN,
	MOUSEUP
};

struct cat_event
{
	enum cat_events type;
	char key;
	unsigned char mouse_button;
	int mousex;
	int mousey;
};

/* SDL stuff */
static unsigned int* fg_framebuffer = NULL;
static unsigned int* bg_framebuffer = NULL;
static unsigned int* comp_framebuffer = NULL;
static SDL_Window* window = NULL;
static SDL_Renderer* renderer = NULL;
static SDL_Texture* texture = NULL;
static int screen_width = 0;
static int screen_height = 0;
/* audio */
static unsigned int wav_length;
static unsigned char* wav_buffer;
static SDL_AudioSpec wav_spec;
static SDL_AudioDeviceID device_id = 0;
static int cat_audio_playing = 0;

void cat_pixel(int layer, int visible, int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
	if (comp_framebuffer == NULL)
	{
		printf("Warning: tried to write a pixel while screen uninitialized\n");
		return;
	}
	if (x >= screen_width || y >= screen_height)
	{
		printf("Warning: (%u, %u): coordinate off screen\n", x, y);
		return;
	}
	unsigned int draw_color = (r << 16) + (g << 8) + b;
	if (visible) draw_color += 0xff000000;
	if (layer) fg_framebuffer[y * screen_width + x] = draw_color;
	else bg_framebuffer[y * screen_width + x] = draw_color;
}

void cat_de_init_screen(void)
{
	if (window != NULL) SDL_DestroyWindow(window);
	window = NULL;
	renderer = NULL;
	texture = NULL;
	free(fg_framebuffer);
	free(bg_framebuffer);
	free(comp_framebuffer);
	fg_framebuffer = NULL; /* this might be redundant */
	bg_framebuffer = NULL;
	comp_framebuffer = NULL;
}

void cat_create_window(int w, int h)
{
	screen_width = w;
	screen_height = h;
	if (window != NULL || renderer != NULL || texture != NULL) cat_de_init_screen();
	fg_framebuffer = malloc(screen_width * screen_height * sizeof(unsigned int));
	bg_framebuffer = malloc(screen_width * screen_height * sizeof(unsigned int));
	comp_framebuffer = malloc(screen_width * screen_height * sizeof(unsigned int));
	window = SDL_CreateWindow("cfhfg", SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED, screen_width, screen_height, SDL_WINDOW_RESIZABLE);
	renderer = SDL_CreateRenderer(window, -1, 0);
	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
		SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height);
	SDL_ShowCursor(SDL_DISABLE);
}

void comp_buffers(void)
{
	int x, y; for (y = 0; y < screen_height; y++)
	{
		for (x = 0; x < screen_width; x++)
		{
			if (fg_framebuffer[y * screen_width + x] & 0xff000000)
				comp_framebuffer[y * screen_width + x] = fg_framebuffer[y * screen_width + x];
			else comp_framebuffer[y * screen_width + x] = bg_framebuffer[y * screen_width + x] | 0xff000000;
											/* TODO decide if this should be left
											   as 0 if "erasing", to make a black
											   pixel, ignoring other color info */
		}
	}
}

void cat_render(void)
{
	comp_buffers();
	SDL_UpdateTexture(texture, NULL, (const void*)comp_framebuffer, screen_width * sizeof(unsigned int));
	SDL_RenderCopy(renderer, texture, NULL, NULL);
	SDL_RenderPresent(renderer);
}

void cat_init(void)
{
	SDL_Init(SDL_INIT_EVERYTHING);
}

void cat_fill(int layer, int visible, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b)
{
	int cy, cx;
	for (cy = 0; cy < h; cy++)
		for (cx = 0; cx < w; cx++)
			cat_pixel(layer, visible, cx + x, cy + y, r, g, b);
}

void cat_wireframe(int layer, int visible, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b)
{
	int cx; for (cx = 0; cx < w; cx++)
	{
		cat_pixel(layer, visible, x + cx, y, r, g, b);
		cat_pixel(layer, visible, x + cx, y+h, r, g, b);
	}
	int cy; for (cy = 0; cy < h; cy++)
	{
		cat_pixel(layer, visible, x, y + cy, r, g, b);
		cat_pixel(layer, visible, x + w, y + cy, r, g, b);
	}
}

/* TODO: cat bresenham */

/* audio... */

void cat_stop_audio(void) {
	SDL_PauseAudioDevice(device_id, 1);
	SDL_CloseAudioDevice(device_id);
	SDL_FreeWAV(wav_buffer);
	cat_audio_playing = 0;
	/*SDL_Quit();*/
}

void cat_play_wav(char* file)
{
	if (cat_audio_playing) cat_stop_audio();
	cat_audio_playing = 1;
	if (SDL_LoadWAV(file, &wav_spec, &wav_buffer, &wav_length) == NULL) {
		printf("file is null!!\n");
		return;
	}
	device_id = SDL_OpenAudioDevice(NULL, 0, &wav_spec, NULL, 0);
	SDL_QueueAudio(device_id, wav_buffer, wav_length);
	SDL_PauseAudioDevice(device_id, 0);
}

struct cat_event* cat_get_event(void)
{
	struct cat_event* out = malloc(sizeof(struct cat_event));
	SDL_Event e;
	(void)SDL_PollEvent(&e);
	if (e.type == SDL_QUIT) out->type = QUIT;
	else if (e.type == SDL_KEYDOWN)
	{
		out->type = KEYDOWN;
		out->key = (e.key.keysym.sym);
	}
	else if (e.type == SDL_KEYUP)
	{
		out->type = KEYUP;
		out->key = (e.key.keysym.sym);
	}
	else if (e.type == SDL_MOUSEMOTION)
	{
		out->type = MOUSEMOVE;
		out->mousex = e.motion.x;
		out->mousey = e.motion.y;
	}
	else if (e.type == SDL_MOUSEBUTTONDOWN)
	{
		out->type = MOUSEDOWN;
		out->mouse_button = e.button.button;
	}
	else if (e.type == SDL_MOUSEBUTTONUP)
	{
		out->type = MOUSEUP;
		out->mouse_button = e.button.button;
	}
	else return NULL;
	return out;
}
