/**
 * projectM -- Milkdrop-esque visualisation SDK
 * Copyright (C)2003-2008 projectM Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * See 'LICENSE.txt' included within this release
 *
 */

#include "video_init.h"
#include <projectM.hpp>
#include "sdltoprojectM.h"
#include "ConfigFile.h"
#include "getConfigFilename.h"

// FIXME: portable includes?
// i just added what works for me -fatray
#include <GL/gl.h>
#include <assert.h>

projectM *globalPM= NULL;

// window stuff
int wvw, wvh, fvw, fvh;
bool fullscreen;

void renderLoop();

// texture test
bool doTextureTest = false;
void textureTest();

// memleak test
bool doMemleakTest = true;
int memLeakIterations = 100;

int main(int argc, char **argv) {

	// fix `fullscreen quit kills mouse` issue.
	atexit(SDL_Quit);

	std::string config_filename = getConfigFilename();
	ConfigFile config(config_filename);

	// window dimensions from configfile
	wvw = config.read<int>("Window Width", 512);
	wvh = config.read<int>("Window Height", 512);
	fullscreen = config.read("Fullscreen", true);

	init_display(wvw, wvh, &fvw, &fvh, fullscreen);

	SDL_WM_SetCaption(PROJECTM_TITLE, NULL);

	// memleak test
	while (doMemleakTest) {
		static int k = 0;
		std::cerr << "[iter " << k++ << "]" << std::endl;
		globalPM = new projectM(config_filename);
		assert(globalPM);
		delete (globalPM);
		if (k >= memLeakIterations)
			break;
	}

	globalPM = new projectM(config_filename);

	// if started fullscreen, give PM new viewport dimensions
	if (fullscreen)
		globalPM->projectM_resetGL(fvw, fvh);

	renderLoop();

	// not reached
	return 1;
}

void renderLoop() {
	while (1) {
		projectMEvent evt;
		projectMKeycode key;
		projectMModifier mod;

		/** Process SDL events */
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			/** Translate into projectM codes and process */
			evt = sdl2pmEvent(event);
            key = sdl2pmKeycode(event.key.keysym.sym,event.key.keysym.mod);
			mod = sdl2pmModifier(event.key.keysym.mod);

			switch (evt) {
			case PROJECTM_KEYDOWN:
				switch (key) {
				case PROJECTM_K_ESCAPE:
					delete(globalPM);
					exit(0);
					break;
				case PROJECTM_K_f: {
					fullscreen = !fullscreen;
					if (fullscreen) {
						resize_display(fvw, fvh, fullscreen);
						globalPM->projectM_resetGL(fvw, fvh);
					} else {
						resize_display(wvw, wvh, fullscreen);
						globalPM->projectM_resetGL(wvw, wvh);
					}
					break;
				}
				case PROJECTM_K_q:
					exit(1);
					break;
				default:
					globalPM->key_handler(evt, key, mod);
				}
				break;

			case PROJECTM_VIDEORESIZE:
				wvw = event.resize.w;
				wvh = event.resize.h;
				resize_display(wvw, wvh, 0);
				globalPM->projectM_resetGL(wvw, wvh);
				break;

			default:
				// not for us, give it to projectM
				globalPM->key_handler(evt, key, mod);
				break;
			}
		}

		globalPM->renderFrame();

		if (doTextureTest)
			textureTest();

		SDL_GL_SwapBuffers();
	}
}

void textureTest() {
	static int textureHandle = globalPM->initRenderToTexture();
	static int frame = 0;
	frame++;

	glClear(GL_COLOR_BUFFER_BIT);
	glClear(GL_DEPTH_BUFFER_BIT);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	if (fullscreen)
		glViewport(0, 0, fvw, fvh);
	else
		glViewport(0, 0, wvw, wvh);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(-1, 1, -1, 1, 2, 10);

	glEnable(GL_DEPTH_TEST);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glTranslatef(cos(frame*0.023), cos(frame*0.017), -5+sin(frame*0.022)*2);
	glRotatef(sin(frame*0.0043)*360, sin(frame*0.0017)*360, sin(frame *0.0032)
			*360, 1);

	glEnable(GL_TEXTURE_2D);
	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();

	glBindTexture(GL_TEXTURE_2D, textureHandle);
	glColor4d(1.0, 1.0, 1.0, 1.0);

	glBegin(GL_QUADS);
	glTexCoord2d(0, 1);
	glVertex3d(-0.8, 0.8, 0);
	glTexCoord2d(0, 0);
	glVertex3d(-0.8, -0.8, 0);
	glTexCoord2d(1, 0);
	glVertex3d(0.8, -0.8, 0);
	glTexCoord2d(1, 1);
	glVertex3d(0.8, 0.8, 0);
	glEnd();

	glDisable(GL_TEXTURE_2D);

	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_DEPTH_TEST);
}

