#include "includes.h"

#include "scene/scene.h"
#include "render/renderer.h"
#include "file_helpers.h"
#include "texture.h"

#include "points.h"

#define DEFAULT_NAME "ray-traced-image.bmp"

SDL_Surface* screen;

Renderer* renderer;

bool paused = false;

void save(const char* name) {
	printf("Saving image as \"%s\".\n",name);
	save_surface(renderer->get_image(),name);
}
bool input(void) {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
			case SDL_KEYDOWN:
				switch (event.key.keysym.sym) {
					case SDLK_ESCAPE:
						return false;
						break;
					case SDLK_s:
						if (renderer->is_finished()) {
							save(DEFAULT_NAME);
						}
						break;
					case SDLK_p:
						paused = !paused;
						(paused) ? renderer->stop() : renderer->start();
						break;
					default:
						break;
				}
				break;
			case SDL_QUIT:
				return false;
				break;
			#ifdef DEBUG_CLICK
			case SDL_MOUSEBUTTONDOWN:
				int x,y;
				SDL_GetMouseState(&x,&y);
				renderer->trace_debug(x,renderer->get_image_height()-y);
				break;
			#endif
			default:
				break;
		}
	}
	return true;
}
void draw(void) {
	if (screen!=NULL) { //Can happen on remote machines
		SDL_BlitSurface(renderer->get_image(),NULL,screen,NULL);
		SDL_Flip(screen);
	}
}
void init(void) {
	SDL_Init(SDL_INIT_EVERYTHING|SDL_INIT_NOPARACHUTE); //TODO: Valgrind gives warning here; Google is unhelpful
	IMG_Init(0xFFFFFFFF);
}
void quit(int status=EXIT_SUCCESS) {
	IMG_Quit();
	SDL_Quit();

	#ifdef CRT
	#ifdef WIN32
	int leaks = _CrtDumpMemoryLeaks();
	if (leaks) {
		throw glLib::error("Memory leak detected!");
	}
	#endif
	#endif

	exit(status);
}

#ifdef SAVE_INTERMEDIARY
void setup_cache(Scene* scene) {
	printf("Examining cache\n");
	if (is_directory(RENDER_TEMPDIR_NAME)) {
		if (exists_file(RENDER_TEMPDIR_SCENE)) {
			char* file = file_get_file( RENDER_TEMPDIR_SCENE.c_str() );
			if (strcmp(scene->parser->file,file)!=0) {
				printf("  Cache is outdated; removing\n");
				remove_directory(RENDER_TEMPDIR_NAME);
			}
			else printf("  Cache is valid\n");
			free((void*)file);
		}
		else {
			printf("  Cache is corrupted; removing\n");
			remove_directory(RENDER_TEMPDIR_NAME);
		}
	}
	else printf("  No cache found\n");
	if (!is_directory(RENDER_TEMPDIR_NAME)) {
		printf("  Creating new cache\n");
		make_directory(RENDER_TEMPDIR_NAME);
		FILE* file = fopen(RENDER_TEMPDIR_SCENE.c_str(),"w");
		if (file==NULL) printf("  Could not open scene caching file!\n");
		else {
			fwrite(scene->parser->file,1,strlen(scene->parser->file),file);
			fclose(file);
			printf("  Successfully wrote scene caching file to cache\n");
		}
	}
}
#endif
int main(int argc, char **argv) {
	#ifdef CRT
	#ifdef WIN32
	_CrtSetDbgFlag(0xFFFFFFFF);
	//_crtBreakAlloc = ;
	#endif
	#endif

	printf("Ian Mallett's C++ Ray Tracer\n");
	printf("  Constructed for CS413/CS513, Fall 2011\n");

	init();

	printf("\nLoading scene.\n");
	Scene* scene = new Scene("data/scene.txt");
	if (scene->valid) {
		SDL_WM_SetCaption("CS 413 HW 4 (Ray Tracer) Ian Mallett 2011",NULL);

		screen = SDL_SetVideoMode(scene->image->width,scene->image->height,32,SDL_DOUBLEBUF);
		SDL_Surface* image = SDL_CreateRGBSurface(SDL_SWSURFACE,scene->image->width,scene->image->height,24,0,0,0,0);

		glLib::Time::clock clk;

		printf("\nSetting up renderer\n");
		renderer = new Renderer(scene,image);

		SDL_Delay(1000);

#if 0
		//printf("  Constructing scene\n");
		//renderer->construct_scene();

		list<PoissonPoint*>* points = generate_poisson_square(2000);
		int i=0;
		for (list<PoissonPoint*>::const_iterator iter=points->begin();iter!=points->end();++iter) {
			int inten = 255;//(int)(255.0*(i++)/(points->size()-1.0));
			Uint32 pixel = SDL_MapRGB(image->format,inten,inten,inten);
			int x = (int)( (scene->image-> width-1) * (*iter)->x );
			int y = (int)( (scene->image->height-1) * (*iter)->y );
			//printf("Setting at %d, %d\n",x,y);
			renderer->set_pixel_rgb24(x,y,pixel,image);
			delete *iter;
			i++;
		}
		printf("%d points were plotted\n",i);
		delete points;
		save("blah.bmp");

		//getchar();
#endif

		#ifdef SAVE_INTERMEDIARY
		setup_cache(scene);
		#endif

		printf("\nRendering scene\n");
		renderer->start();

		bool has_measured_time = false;
		while (true) {
			if (!has_measured_time&&renderer->is_finished()) {
				printf("\rCompleted scene in ");
				renderer->print_time();
				printf(".                   \n");
				has_measured_time = true;
				if (screen==NULL) { //On remote machines
					save(DEFAULT_NAME);
					break;
				}
			}

			if (input()==false) break;
			draw();
			clk.tick(30.0);
		}

		#ifdef SAVE_INTERMEDIARY
		if (renderer->finished&&is_directory(RENDER_TEMPDIR_NAME)) remove_directory(RENDER_TEMPDIR_NAME);
		#endif

		delete renderer;

		SDL_FreeSurface(image);
		SDL_FreeSurface(screen);
	}
	else {
		printf("There was an error loading the scene:\n");
		scene->print_error(2);
		printf("Press ENTER to exit.\n");
		getchar();
	}
	delete scene;

	quit();

	return 0;
}