/***************************************************************************
 *   Copyright (C) 2005 by Peter Müller                                    *
 *   pmueller@cs.tu-berlin.de                                              *
 *   Copyright (C) 2008 by John Stamp <jstamp@users.sourceforge.net>       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
 ***************************************************************************/

#include "kglcometen4.h"
#include "cometenmath.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QImage>
#include <KConfigGroup>


KGLCometen4::KGLCometen4(QWidget *parent)
: QGLWidget(parent)
{
	loadConfig();
	cometen3 = new Cometen3();
	textures = new GLuint[T_NUM];
}

KGLCometen4::~KGLCometen4() {
	delete cometen3;
	delete[] textures;
}

void KGLCometen4::loadConfig()
{
	// only do it once
	if ( !settings.isEmpty() )
		return;

	KConfigGroup config( KGlobal::config(), "Settings" );

	// Since we're using a list we have to make sure that these values are
	// appended in the same order as the enum.

	// General
	settings.append( config.readEntry("color", 0));
	settings.append( clamp<double>(config.readEntry("interval", 1.25), 0.1, 10.0));
	settings.append( clamp<double>(config.readEntry("timescale", 1.0), 0.1, 5.0) );
	settings.append( clamp<double>(config.readEntry("sizescale", 2.5), 0.5, 5.0) );
	settings.append( clamp<double>(config.readEntry("fov", 76.0), 10.0, 120.0) );
	settings.append( clamp<int>(10, 999, config.readEntry("maxfps", 60)) );
	settings.append( config.readEntry( "cube", false ) );
	settings.append( config.readEntry( "freecamera", true ) );
	settings.append( clamp<double>(config.readEntry("freecamspeed", 1.5), 0.0, 10.0) );
	// Effects
	settings.append( config.readEntry( "curvecomet", true ) );
	settings.append( config.readEntry( "rotatecomet", true ) );
	settings.append( config.readEntry( "splitcomet", true ) );
	settings.append( config.readEntry( "lightning", true ) );
	settings.append( config.readEntry( "slowmotion", true ) );
	settings.append( config.readEntry( "matrix", true ) );
	// Background
	settings.append( config.readEntry("bgtype", 0) );
	settings.append( config.readEntry("bgfile","") );
	settings.append( config.readEntry("bgdir","") );
	settings.append( config.readEntry("bgsize", 2) );
	settings.append( config.readEntry("mipmaps", false) );

	// Let's also add an assert to make sure we don't later access nonexistent
	// items.
	assert( settings.size() == SE_NUM );
}

void KGLCometen4::start()
{
	cometen3->updateSettings(t.elapsed() / 1000.0);
	m_timerId = startTimer(1000/settings.at(SE_MAXFPS).toInt());
}

void KGLCometen4::stop()
{
	killTimer( m_timerId );
}

void KGLCometen4::updateBackground()
{
	QImage image;
	
	srand(time(NULL));

	if (settings.at(SE_BGTYPE).toInt() == 2) {
		QString file = randomFileFromDir(settings.at(SE_BGDIR).toString());
		if (!image.load(file)) {
			image = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
		}
	}
	else if (settings.at(SE_BGTYPE).toInt() == 1) {
		if (!image.load(settings.at(SE_BGFILE).toString())) {
			image = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
		}
	}
	else {
		image = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
	}
	
	switch (settings.at(SE_BGSIZE).toInt()) {
	case 0:
		image = image.scaled(128, 128, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
		break;
	case 1:
		image = image.scaled(256, 256, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
		break;
	case 2:
		image = image.scaled(512, 512, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
		break;
	case 3:
		image = image.scaled(1024, 1024, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
		break;
	case 4:
	default:
		break;
	}
		
	image = QGLWidget::convertToGLFormat(image);


	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &textures[T_BACKGROUND]);
	glBindTexture(GL_TEXTURE_2D, textures[T_BACKGROUND]); 

	if (settings.at(SE_BGMIPMAPS).toBool())
	{
		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.width(), image.height(),
		                  GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
	}
	else
	{
		glTexImage2D(GL_TEXTURE_2D, 0, 3, image.width(), image.height(),
		             0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	}
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	
	textures[T_PARTICLE] = loadTexture("particle.png");
	textures[T_LIGHTMAP] = loadTexture("lightmap.png");
}

void KGLCometen4::initializeGL() {
	qglClearColor(QColor(Qt::black));
	updateBackground();

	t.start();
	cometen3->init(textures, 640, 480, t.elapsed() / 1000.0);
}

void KGLCometen4::resizeGL(int res_x, int res_y) {
	cometen3->resize(res_x, res_y);
	if ( res_x == 640 && res_y == 480 )
		emit doResizeHack();
}

void KGLCometen4::updateSizeScale()
{
	cometen3->updateSizeScale();
}

void KGLCometen4::paintGL() {
	cometen3->render();
}

void KGLCometen4::timerEvent(QTimerEvent * ) {
	cometen3->process(t.elapsed() / 1000.0);
	updateGL();
}

QString KGLCometen4::randomFileFromDir(const QString& dirname) {
	QDir dir(dirname, "*.jpg;*.jpeg;*.png;*.gif",
	         QDir::Unsorted, QDir::Files | QDir::Readable);
	
	if (dir.count() < 1) {
		return QString("");
	}
	
	int num = rand() % dir.count();
	
	return dir.absolutePath() + "/" + dir[num];
}

GLuint KGLCometen4::loadTexture(const char* file) {
	QImage image;
	GLuint tex = 0;

	if (image.load(KStandardDirs::locate("data", 
	      QString("kcometen4/pixmaps/") + file))) {
		image = QGLWidget::convertToGLFormat(image);
		
		glEnable(GL_TEXTURE_2D);
		glGenTextures(1, &tex);
		glBindTexture(GL_TEXTURE_2D, tex); 

		if (settings.at(SE_BGMIPMAPS).toBool())
		{
			gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.width(), image.height(),
			                  GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
		}
		else
		{
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.width(), image.height(),
			             0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		}
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	}

	return tex;
}
