/**
 * 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 = true;
void textureTest();

// memleak test
bool doMemleakTest = false;
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);
}

