/***************************************************************************
 *   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 <kaboutapplicationdialog.h>
#include "kcometen4.h"
#include "global.h"
#include <QDesktopWidget>

static KAboutData* s_aboutData = 0;
QVariantList settings;

class KCometen4Interface : public KScreenSaverInterface
{
public:
	virtual KAboutData* aboutData() {
		return s_aboutData;
	}

	/** function to create screen saver object */
	virtual KScreenSaver* create( WId id )
	{
	  return new KCometen4( id );
	}

	/** function to create setup dialog for screen saver */
	virtual QDialog* setup()
	{
	  return new KCometen4Setup();
	}
};


int main( int argc, char*argv[] )
{
	s_aboutData = new KAboutData( "kcometen4.kss", 0,
								ki18n("KCometen4"), "1.0.2",
								ki18n("An OpenGL screensaver with exploding comets."),
								KAboutData::License_GPL,
								ki18n("Copyright (C) 2005 Peter Müller<br>Copyright (C) 2008 John Stamp"),
								KLocalizedString(),
								"http://www.mehercule.net/staticpages/index.php/kcometen4",
								"jstamp@users.sourceforge.net" );
	s_aboutData->addAuthor( ki18n("Peter Müller"),
							ki18n("Original author of <a href=\"http://www.kde-apps.org/content/show.php/KCometen3?content=30313\">KCometen3</a>."),
							"pmueller@cs.tu-berlin.de");
	s_aboutData->addAuthor( ki18n("John Stamp"),
							ki18n("Ported to KDE4 as KCometen4."),
							"jstamp@users.sourceforge.net");

	KCometen4Interface kss;
	return kScreenSaverMain( argc, argv, kss );
}

//-----------------------------------------------------------------------------
//! dialog to setup screen saver parameters
KCometen4Setup::KCometen4Setup( QWidget *parent ) : KDialog( parent )
{
	setCaption( i18n( "Setup KCometen4 Screen Saver" ) );
	setButtons( Ok|Cancel|Help|Default );
	setDefaultButton( Ok );
	setModal( true );
	showButtonSeparator(true);
	setButtonText( Help, i18n( "A&bout" ) );

	QWidget *main = new QWidget( this );
	setMainWidget( main );
	ui.setupUi( main );

	ui.kURLRequesterRandomDirectory->setMode(KFile::Directory);
	buttonGroupBackground.addButton( ui.radioButton3 );
	buttonGroupBackground.addButton( ui.radioButton4 );
	buttonGroupBackground.addButton( ui.radioButton5 );
	buttonGroupBackground.setId( ui.radioButton3, 0 );
	buttonGroupBackground.setId( ui.radioButton4, 1 );
	buttonGroupBackground.setId( ui.radioButton5, 2 );

	// Try to duplicate screen's aspect ratio
	int width = 220;
	int height = 170;
	QRect deskSize = QApplication::desktop()->screenGeometry();
	if ( deskSize.width() > 0 )
		height = (double)width*deskSize.height()/deskSize.width();
	ui.preview->setFixedSize( width, height );

	QPalette p = palette();
	p.setColor( backgroundRole(), Qt::black );
	ui.preview->setPalette( p );

	ui.preview->show();    // otherwise saver does not get correct size
	saver = new KGLCometen4( ui.preview );
	saver->resize( ui.preview->size() );
	saver->start();

	initDialog();  // Do this after we have a saver

	connect( this, SIGNAL( okClicked() ), SLOT( slotOkPressed() ) );
	connect( this, SIGNAL( helpClicked() ), SLOT( slotHelp() ) );
	connect( this, SIGNAL( defaultClicked() ), SLOT( slotDefault() ) );

	connect( ui.comboBoxColor, SIGNAL( currentIndexChanged(int)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.kDoubleNumInputInterval, SIGNAL( valueChanged(double)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.kIntNumInputFps, SIGNAL( valueChanged(int)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.checkIsCube, SIGNAL( toggled(bool)), this, SLOT( updateBoxShape() ) );
	connect( ui.checkFreeCamera, SIGNAL( toggled(bool)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.checkCurveComet, SIGNAL( toggled(bool)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.checkRotateComet, SIGNAL( toggled(bool)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.checkSplitComet, SIGNAL( toggled(bool)), this, SLOT( updateOnTheFlySettings() ) );
	connect( ui.checkBlitz, SIGNAL( toggled(bool)), this, SLOT( updateOnTheFlySettings() ) );

	connect( ui.kDoubleNumInputTimeScale, SIGNAL( valueChanged(double)), this, SLOT( updateStopStartSettings() ) );
	connect( ui.kDoubleNumInputCamSpeed, SIGNAL( valueChanged(double)), this, SLOT( updateStopStartSettings() ) );
	connect( ui.checkSlowmotion, SIGNAL( toggled(bool)), this, SLOT( updateStopStartSettings() ) );
	connect( ui.checkRotCam, SIGNAL( toggled(bool)), this, SLOT( updateStopStartSettings() ) );

	connect( ui.kDoubleNumInputSizeScale, SIGNAL( valueChanged(double)), this, SLOT( updateSizeScale(double) ) );
	connect( ui.kDoubleNumInputFov, SIGNAL( valueChanged(double)), this, SLOT( updateFov(double) ) );

	connect( &buttonGroupBackground, SIGNAL( buttonClicked(int)), this, SLOT( updateBackground() ) );
	connect( ui.kURLRequesterFile, SIGNAL( returnPressed()), this, SLOT( updateBackground() ) );
	connect( ui.kURLRequesterFile, SIGNAL( urlSelected(KUrl)), this, SLOT( updateBackground() ) );
	connect( ui.kURLRequesterRandomDirectory, SIGNAL( returnPressed()), this, SLOT( updateBackground() ) );
	connect( ui.kURLRequesterRandomDirectory, SIGNAL( urlSelected(KUrl)), this, SLOT( updateBackground() ) );
	connect( ui.comboBoxBgSize, SIGNAL( currentIndexChanged(int)), this, SLOT( updateBackground() ) );
	connect( ui.checkMipmaps, SIGNAL( toggled(bool)), this, SLOT( updateBackground() ) );
}

KCometen4Setup::~KCometen4Setup()
{
	delete saver;
}

void KCometen4Setup::slotDefault()
{
	// General
	ui.comboBoxColor->setCurrentIndex(0);
	ui.kDoubleNumInputInterval->setValue(1.25);
	ui.kDoubleNumInputTimeScale->setValue(1.0);
	ui.kDoubleNumInputSizeScale->setValue(2.5);
	ui.kDoubleNumInputFov->setValue(76.0);
	ui.kIntNumInputFps->setValue(60);
	ui.checkIsCube->setChecked(false);
	ui.checkFreeCamera->setChecked(true);
	ui.kDoubleNumInputCamSpeed->setValue(1.5);
	// Effects
	ui.checkCurveComet->setChecked(true);
	ui.checkRotateComet->setChecked(true);
	ui.checkSplitComet->setChecked(true);
	ui.checkBlitz->setChecked(true);
	ui.checkSlowmotion->setChecked(true);
	ui.checkRotCam->setChecked(true);
	// Background
	ui.radioButton3->setChecked(true);
	ui.kURLRequesterFile->setUrl(QString());
	ui.kURLRequesterRandomDirectory->setUrl(QString());
	ui.comboBoxBgSize->setCurrentIndex(2);
	ui.checkMipmaps->setChecked(false);

	saver->stop();

	updateOnTheFlySettings();
	updateStopStartSettings(false);
	updateBackground(false);
	updateSizeScale(ui.kDoubleNumInputSizeScale->value(), false);
	updateFov(ui.kDoubleNumInputFov->value(), false);

	saver->start();
}

void KCometen4Setup::updateBoxShape()
{
	settings[SE_CUBE].setValue( ui.checkIsCube->isChecked() );
	saver->updateSizeScale();
}

// The preview will have already read things into settings
void KCometen4Setup::initDialog()
{
	// General
	ui.comboBoxColor->setCurrentIndex(settings.at(SE_COLORS).toInt());
	ui.kDoubleNumInputInterval->setValue(settings.at(SE_CREATEINTERVAL).toDouble());
	ui.kDoubleNumInputTimeScale->setValue(settings.at(SE_TIMESCALE).toDouble());
	ui.kDoubleNumInputSizeScale->setValue(settings.at(SE_SIZESCALE).toDouble());
	ui.kDoubleNumInputFov->setValue(settings.at(SE_FOV).toDouble());
	ui.kIntNumInputFps->setValue(settings.at(SE_MAXFPS).toInt());
	ui.checkIsCube->setChecked(settings.at(SE_CUBE).toBool());
	ui.checkFreeCamera->setChecked(settings.at(SE_FREECAMERA).toBool());
	ui.kDoubleNumInputCamSpeed->setValue(settings.at(SE_FREECAMERASPEED).toDouble());
	// Effects
	ui.checkCurveComet->setChecked(settings.at(SE_DOCURVECOMET).toBool());
	ui.checkRotateComet->setChecked(settings.at(SE_DOROTATECOMET).toBool());
	ui.checkSplitComet->setChecked(settings.at(SE_DOSPLITCOMET).toBool());
	ui.checkBlitz->setChecked(settings.at(SE_DOBLITZ).toBool());
	ui.checkSlowmotion->setChecked(settings.at(SE_DOSLOWMOTION).toBool());
	ui.checkRotCam->setChecked(settings.at(SE_DOMATRIX).toBool());
	// Background
	int activeButton = settings.at(SE_BGTYPE).toInt();
	switch (activeButton)
	{
	case 0:
		ui.radioButton3->setChecked(true);
		break;
	case 1:
		ui.radioButton4->setChecked(true);
		break;
	case 2:
		ui.radioButton5->setChecked(true);
		break;
	}
	ui.kURLRequesterFile->setUrl(settings.at(SE_BGFILE).toString());
	ui.kURLRequesterRandomDirectory->setUrl(settings.at(SE_BGDIR).toString());
	ui.comboBoxBgSize->setCurrentIndex(settings.at(SE_BGSIZE).toInt());
	ui.checkMipmaps->setChecked(settings.at(SE_BGMIPMAPS).toBool());
}


//! Ok pressed - save settings and exit
void KCometen4Setup::slotOkPressed()
{
	KConfigGroup config( KGlobal::config(), "Settings" );

	// General
	config.writeEntry("color", ui.comboBoxColor->currentIndex());
	config.writeEntry("interval", ui.kDoubleNumInputInterval->value());
	config.writeEntry("timescale", ui.kDoubleNumInputTimeScale->value());
	config.writeEntry("sizescale", ui.kDoubleNumInputSizeScale->value());
	config.writeEntry("fov", ui.kDoubleNumInputFov->value());
	config.writeEntry("maxfps", ui.kIntNumInputFps->value());
	config.writeEntry("cube", ui.checkIsCube->isChecked());
	config.writeEntry("freecamera", ui.checkFreeCamera->isChecked());
	config.writeEntry("freecamspeed", ui.kDoubleNumInputCamSpeed->value());
	// Effects
	config.writeEntry("curvecomet", ui.checkCurveComet->isChecked());
	config.writeEntry("rotatecomet", ui.checkRotateComet->isChecked());
	config.writeEntry("splitcomet", ui.checkSplitComet->isChecked());
	config.writeEntry("lightning", ui.checkBlitz->isChecked());
	config.writeEntry("slowmotion", ui.checkSlowmotion->isChecked());
	config.writeEntry("matrix", ui.checkRotCam->isChecked());
	// Background
	config.writeEntry("bgtype", buttonGroupBackground.checkedId());
	config.writeEntry("bgfile", ui.kURLRequesterFile->url().path());
	config.writeEntry("bgdir", ui.kURLRequesterRandomDirectory->url().path());
	config.writeEntry("bgsize", ui.comboBoxBgSize->currentIndex());
	config.writeEntry("mipmaps", ui.checkMipmaps->isChecked());

	config.sync();

	accept();
}

void KCometen4Setup::updateOnTheFlySettings()
{
	settings[SE_COLORS].setValue( ui.comboBoxColor->currentIndex() );
	settings[SE_CREATEINTERVAL].setValue( ui.kDoubleNumInputInterval->value() );
	settings[SE_MAXFPS].setValue( ui.kIntNumInputFps->value() );
	settings[SE_FREECAMERA].setValue( ui.checkFreeCamera->isChecked() );
	settings[SE_DOCURVECOMET].setValue( ui.checkCurveComet->isChecked() );
	settings[SE_DOROTATECOMET].setValue( ui.checkRotateComet->isChecked() );
	settings[SE_DOSPLITCOMET].setValue( ui.checkSplitComet->isChecked() );
	settings[SE_DOBLITZ].setValue( ui.checkBlitz->isChecked() );
}

void KCometen4Setup::updateStopStartSettings(bool forceStopStart)
{
	if (forceStopStart)
		saver->stop();

	settings[SE_TIMESCALE].setValue( ui.kDoubleNumInputTimeScale->value() );
	settings[SE_FREECAMERASPEED].setValue( ui.kDoubleNumInputCamSpeed->value() );
	settings[SE_DOSLOWMOTION].setValue( ui.checkSlowmotion->isChecked() );
	settings[SE_DOMATRIX].setValue( ui.checkRotCam->isChecked() );

	if (forceStopStart)
		saver->start();
}

void KCometen4Setup::updateBackground(bool forceStopStart)
{
	if (forceStopStart)
		saver->stop();

	settings[SE_BGTYPE].setValue( buttonGroupBackground.checkedId() );
	settings[SE_BGFILE].setValue( ui.kURLRequesterFile->url().path() );
	settings[SE_BGDIR].setValue( ui.kURLRequesterRandomDirectory->url().path() );
	settings[SE_BGSIZE].setValue( ui.comboBoxBgSize->currentIndex() );
	settings[SE_BGMIPMAPS].setValue( ui.checkMipmaps->isChecked() );
	saver->updateBackground();

	if (forceStopStart)
		saver->start();
}

void KCometen4Setup::updateSizeScale( double scale, bool forceStopStart )
{
	if (forceStopStart)
		saver->stop();

	settings[SE_SIZESCALE].setValue( scale );
	saver->updateSizeScale();

	if (forceStopStart)
		saver->start();
}


void KCometen4Setup::updateFov( double fov, bool forceStopStart )
{
	if (forceStopStart)
		saver->stop();

	settings[SE_FOV].setValue( fov );
	saver->updateSizeScale();

	if (forceStopStart)
		saver->start();
}


void KCometen4Setup::slotHelp()
{
	KAboutApplicationDialog mAbout(s_aboutData, this);
	mAbout.exec();
}


//-----------------------------------------------------------------------------


KCometen4::KCometen4( WId id ) : KScreenSaver( id )
{
	QPalette p = palette();
	p.setColor( backgroundRole(), Qt::black );
	setPalette( p );

	kglcometen4 = new KGLCometen4();

	embed(kglcometen4);

	kglcometen4->start();

	// Show last to avoid occasional flicker on startup
	kglcometen4->show();

	// Occasionally on startup the embedded QGLWidget resizes to 640x480 *after*
	// it gets correctly sized.  The OpenGL screensavers in the kdeartwork
	// package suffer from this too, but I have no idea what's causing it.
	//
	// Let's work around it: kglcometen4 emits doResizeHack() when it's sized to
	// 640x480.  We then listen only for the first time it's emitted, and resize
	// it back to what it should be.
	connect( kglcometen4, SIGNAL( doResizeHack() ), this, SLOT( resizeHack() ) );
}

void KCometen4::resizeHack()
{
	disconnect( kglcometen4, SIGNAL( doResizeHack() ), 0, 0 );
	kglcometen4->resize( width(), height() );
}

void KCometen4::resizeEvent( QResizeEvent * )
{
	if ( kglcometen4 )
	{
		kglcometen4->stop();
		kglcometen4->resize( width(), height() );
		kglcometen4->start();
	}
}

KCometen4::~KCometen4()
{
	delete kglcometen4;
}

