/*****************************************************************************
 *
 *  preferencesdialog.cpp -- Set application preferences->
 *
 *  Copyright (C) 2010 Starbuck <starbuck@labdv.com>
 *  All rights reserved.
 *
 *  This file is part of the Gui4 module of the DVDx 4 application.
 *
 *  GNU Lesser General Public License Usage
 *  This file may be used under the terms of the GNU Lesser General
 *  Public License version 2.1 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.LGPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU Lesser General Public License version 2.1 requirements
 *  will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 *  GNU General Public License Usage
 *  Alternatively, this file may be used under the terms of the GNU
 *  General Public License version 3.0 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.GPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU General Public License version 3.0 requirements will be
 *  met: http://www.gnu.org/copyleft/gpl.html.
 *
 *****************************************************************************/

#include "preferencesdialog.h"
#include <QLayout>
#include <QLabel>
#include <QLineEdit>
#include <QGroupBox>
#include <QPushButton>
#include <QFile>
#include <QRegExp>

PreferencesDialog::PreferencesDialog(MainWindow::Preferences *preferences,
			QWidget *parent)
	: QDialog(parent)
{
	setWindowTitle( tr("Preferences") );
	
	this->preferences = preferences;
	this->mainWindow = (MainWindow *) parent;

	tabWidget = new QTabWidget(this);
	tabWidget->setMovable(false);

	mainTab = new QWidget();
	timingTab = new QWidget();

	tabWidget->addTab(mainTab, QString( tr("General") ));
	tabWidget->addTab(timingTab, QString( tr("Timing") ));

	buttonBox = new QDialogButtonBox(this);
	buttonBox->setFocusPolicy(Qt::StrongFocus);
	buttonBox->setOrientation(Qt::Horizontal);
	buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
	buttonBox->setCenterButtons(true);

	verticalLayout = new QVBoxLayout(this);
	verticalLayout->addWidget(tabWidget);
	verticalLayout->addWidget(buttonBox);

	tabWidget->setCurrentIndex(0);

	QPushButton *resetButton = new QPushButton( tr("Default all"), this);
	resetButton->setToolTip( tr("Set all preferences to default") );
	QSpacerItem *resetHSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);

	QHBoxLayout *resetHLayout = new QHBoxLayout;
	resetHLayout->addWidget(resetButton);
	resetHLayout->addItem(resetHSpacer);

	QPushButton *resetTimingButton = new QPushButton( tr("Default timing"), this);
	resetTimingButton->setToolTip( tr("Reset timing preferences to default") );
	QSpacerItem *resetTimingHSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);

	QHBoxLayout *resetTimingHLayout = new QHBoxLayout;
	resetTimingHLayout->addWidget(resetTimingButton);
	resetTimingHLayout->addItem(resetTimingHSpacer);

	QLabel *dvdTitleMinLengthLabel = new QLabel( tr("Short titles to ignore:"), this);
	dvdTitleMinLengthEdit = new QLineEdit(this);
	dvdTitleMinLengthEdit->setToolTip( tr("Not < 10.0 seconds") );
	dvdIgnoreShortTitles = new QCheckBox(this);

	dvdTitleMinLengthLabel->setToolTip( tr("Threshold in seconds to filter out short titles") );
	dvdIgnoreShortTitles->setToolTip( tr("Uncheck to keep all titles when loading") );

	QGridLayout *dvdPreferences = new QGridLayout;
	dvdPreferences->addWidget(dvdTitleMinLengthLabel,	0, 0);
	dvdPreferences->addWidget(dvdTitleMinLengthEdit,	0, 1);
	dvdPreferences->addWidget(dvdIgnoreShortTitles,		0, 2);

	QGroupBox *dvdPreferencesGroup = new QGroupBox(tr("DVD preferences"));
	dvdPreferencesGroup->setLayout(dvdPreferences);

	QLabel *numTestFramesLabel = new QLabel( tr("Frames:"), this);
	numTestFramesEdit = new QLineEdit(this);
	numTestFramesEdit->setToolTip( tr("Not < 100 frames") );

	numTestFramesLabel->setToolTip( tr("Number of frames to encode in test mode (MEncoder)") );
	
	QLabel *numTestChapterLabel = new QLabel( tr("Chapter:"), this);
	numTestChapterEdit = new QLineEdit(this);
	numTestChapterEdit->setToolTip( tr("Not < 1") );

	numTestChapterLabel->setToolTip( tr("Start encoding test from this chapter (MEncoder)") );
	
	QLabel *numTestPositionLabel = new QLabel( tr("Seek position:"), this);
	numTestPositionEdit = new QLineEdit(this);
	numTestPositionEdit->setToolTip( tr("Not < 0 second") );

	numTestPositionLabel->setToolTip( tr("Start encoding test from this position in seconds (FFmpeg)") );

	QGridLayout *testMode = new QGridLayout;
	testMode->addWidget(numTestFramesLabel,		0, 0);
	testMode->addWidget(numTestFramesEdit,		0, 1);
	testMode->addWidget(numTestChapterLabel,	1, 0);
	testMode->addWidget(numTestChapterEdit,		1, 1);
	testMode->addWidget(numTestPositionLabel,	2, 0);
	testMode->addWidget(numTestPositionEdit,	2, 1);

	QGroupBox *testModeGroup = new QGroupBox(tr("Encoder test mode"));
	testModeGroup->setLayout(testMode);

	QLabel *numFramesToValidLabel = new QLabel( tr("Frames to validate:"), this);
	numFramesToValidEdit = new QLineEdit(this);
	numFramesToValidEdit->setToolTip( tr("Not < 25 frames") );

	numFramesToValidLabel->setToolTip( tr("Number of frames to encode to validate an encoder command (MEncoder)") );
	
	QLabel *numSizeToValidLabel = new QLabel( tr("File size to validate:"), this);
	numSizeToValidEdit = new QLineEdit(this);
	numSizeToValidEdit->setToolTip( tr("Not < 10000 Bytes") );

	numSizeToValidLabel->setToolTip( tr("File output size to encode to validate an encoder command (FFmpeg)") );

	QGridLayout *encoderSettings = new QGridLayout;
	encoderSettings->addWidget(numFramesToValidLabel,	0, 0);
	encoderSettings->addWidget(numFramesToValidEdit,	0, 1);
	encoderSettings->addWidget(numSizeToValidLabel,		1, 0);
	encoderSettings->addWidget(numSizeToValidEdit,		1, 1);

	QGroupBox *encoderGroup = new QGroupBox(tr("Encoder"));
	encoderGroup->setLayout(encoderSettings);

	QLabel *outputNameLabel = new QLabel( tr("File name:"), this);
	outputNameEdit = new QLineEdit(this);
	forceOutputName = new QCheckBox(this);

	outputNameLabel->setToolTip( tr("Output base file name") );
	outputNameEdit->setToolTip( tr("Default: output") );
	forceOutputName->setToolTip( tr("Uncheck to use intput name for output") );
	
	QGridLayout *outputTargetPreferences = new QGridLayout;
	outputTargetPreferences->addWidget(outputNameLabel,		0, 0);
	outputTargetPreferences->addWidget(outputNameEdit,		0, 1);
	outputTargetPreferences->addWidget(forceOutputName,		0, 2);

	QGroupBox *outputTargetPreferencesGroup = new QGroupBox(tr("Output target"));
	outputTargetPreferencesGroup->setLayout(outputTargetPreferences);

	QLabel *encLatencyStartLabel = new QLabel( tr("Start:"), this);
	encLatencyStartEdit = new QLineEdit(this);
	QLabel *encLatencyFinishedLabel = new QLabel( tr("Finished:"), this);
	encLatencyFinishedEdit = new QLineEdit(this);
	QLabel *encLatencyKillLabel = new QLabel( tr("Kill:"), this);
	encLatencyKillEdit = new QLineEdit(this);

	encLatencyStartEdit->setToolTip( tr("Not < 1000 milliseconds") );
	encLatencyFinishedEdit->setToolTip( tr("Not < 1000 milliseconds") );
	encLatencyKillLabel->setToolTip( tr("Not < 1000 milliseconds") );

	encLatencyStartLabel->setToolTip( tr("Milliseconds to wait encoder process started") );
	encLatencyFinishedLabel->setToolTip( tr("Milliseconds to wait encoder process finished") );
	encLatencyKillLabel->setToolTip( tr("Milliseconds to wait encoder process not responding") );
	
	QGridLayout *encLatency = new QGridLayout;
	encLatency->addWidget(encLatencyStartLabel,		0, 0);
	encLatency->addWidget(encLatencyStartEdit,		0, 1);
	encLatency->addWidget(encLatencyFinishedLabel,	1, 0);
	encLatency->addWidget(encLatencyFinishedEdit,	1, 1);
	encLatency->addWidget(encLatencyKillLabel,		2, 0);
	encLatency->addWidget(encLatencyKillEdit,		2, 1);

	QGroupBox *encLatencyGroup = new QGroupBox(tr("Encoder latency"));
	encLatencyGroup->setLayout(encLatency);

	QLabel *playLatencyStartLabel = new QLabel( tr("Start:"), this);
	playLatencyStartEdit = new QLineEdit(this);
	QLabel *playLatencyFinishedLabel = new QLabel( tr("Finished:"), this);
	playLatencyFinishedEdit = new QLineEdit(this);
	QLabel *playLatencyKillLabel = new QLabel( tr("Kill:"), this);
	playLatencyKillEdit = new QLineEdit(this);
	QLabel *playPollTicksLabel = new QLabel( tr("Poll ticks:"), this);
	playPollTicksEdit = new QLineEdit(this);

	playLatencyStartEdit->setToolTip( tr("Not < 1000 milliseconds") );
	playLatencyFinishedEdit->setToolTip( tr("Not < 1000 milliseconds") );
	playLatencyKillEdit->setToolTip( tr("Not < 1000 milliseconds") );
	playPollTicksEdit->setToolTip( tr("Not < 500 milliseconds") );

	playLatencyStartLabel->setToolTip( tr("Milliseconds to wait player process started") );
	playLatencyFinishedLabel->setToolTip( tr("Milliseconds to wait player process finished") );
	playLatencyKillLabel->setToolTip( tr("Milliseconds to wait player process not responding") );
	playPollTicksLabel->setToolTip( tr("Poll player process every milliseconds to update controls") );
	
	QGridLayout *playLatency = new QGridLayout;
	playLatency->addWidget(playLatencyStartLabel,		0, 0);
	playLatency->addWidget(playLatencyStartEdit,		0, 1);
	playLatency->addWidget(playLatencyFinishedLabel,	1, 0);
	playLatency->addWidget(playLatencyFinishedEdit,		1, 1);
	playLatency->addWidget(playLatencyKillLabel,		2, 0);
	playLatency->addWidget(playLatencyKillEdit,			2, 1);
	playLatency->addWidget(playPollTicksLabel,			3, 0);
	playLatency->addWidget(playPollTicksEdit,			3, 1);

	QGroupBox *playLatencyGroup = new QGroupBox(tr("Player latency"));
	playLatencyGroup->setLayout(playLatency);

	QVBoxLayout *mainLayout = new QVBoxLayout(mainTab);
	QSpacerItem *mainVSpacer = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding);
	mainLayout->addWidget(dvdPreferencesGroup);
	mainLayout->addWidget(testModeGroup);
	mainLayout->addWidget(encoderGroup);
	mainLayout->addWidget(outputTargetPreferencesGroup);	
	mainLayout->addItem(mainVSpacer);
	mainLayout->addLayout(resetHLayout);
	
	QVBoxLayout *timingLayout = new QVBoxLayout(timingTab);
	QSpacerItem *timingVSpacer = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding);
	timingLayout->addWidget(encLatencyGroup);
	timingLayout->addWidget(playLatencyGroup);
	timingLayout->addItem(timingVSpacer);
	timingLayout->addLayout(resetTimingHLayout);

	setLayout(verticalLayout);

	QObject::connect(resetButton, SIGNAL(clicked()), this, SLOT(resetPreferences()));
	QObject::connect(resetTimingButton, SIGNAL(clicked()), this, SLOT(resetTimingPreferences()));

	QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
	QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

	setAttribute(Qt::WA_AlwaysShowToolTips);
	setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
	setMinimumWidth( 260 );

	setControlValues();
}

void PreferencesDialog::accept()
{
	EncoderWidget::Preferences encoderPreferencesDefault;
	QString output_name = QFile::encodeName(outputNameEdit->text());
	output_name = output_name.replace( QRegExp("[\\\\/?*|]"), "" );
	output_name = output_name.simplified();
	if (output_name.isEmpty()) output_name = encoderPreferencesDefault.output_name;

	preferences->encoderPreferences.test_frames = qMax(numTestFramesEdit->text().toInt(), 100);
	preferences->encoderPreferences.test_chapter = qMin(99, qMax(numTestChapterEdit->text().toInt(), 1));
	preferences->encoderPreferences.test_position = qMax(numTestPositionEdit->text().toInt(), 0);

	preferences->encoderPreferences.validation_frames = qMin(100, qMax(numFramesToValidEdit->text().toInt(), 25));
	preferences->encoderPreferences.validation_size = qMin(2000000, qMax(numSizeToValidEdit->text().toInt(), 500000));

	preferences->encoderPreferences.force_output_name = forceOutputName->isChecked();
	preferences->encoderPreferences.output_name = output_name;

	preferences->encoderPreferences.latency_start = qMin(5000, qMax(encLatencyStartEdit->text().toInt(), 1000));
	preferences->encoderPreferences.latency_finished = qMin(5000, qMax(encLatencyFinishedEdit->text().toInt(), 1000));
	preferences->encoderPreferences.latency_kill = qMin(5000, qMax(encLatencyKillEdit->text().toInt(), 3000));

	preferences->playerPreferences.dvd_ignore_short_titles = dvdIgnoreShortTitles->isChecked();
	preferences->playerPreferences.dvd_title_min_length = qMin(3600.0 * 2.0, qMax(dvdTitleMinLengthEdit->text().toDouble(), 60.0));

	preferences->playerPreferences.latency_start = qMin(5000, qMax(playLatencyStartEdit->text().toInt(), 1000));
	preferences->playerPreferences.latency_finished = qMin(5000, qMax(playLatencyFinishedEdit->text().toInt(), 1000));
	preferences->playerPreferences.latency_kill = qMin(5000, qMax(playLatencyKillEdit->text().toInt(), 3000));
	preferences->playerPreferences.poll_ticks = qMin(2000, qMax(playPollTicksEdit->text().toInt(), 500));

	preferences->playerPreferences.test_frames = preferences->encoderPreferences.test_frames;
	preferences->playerPreferences.test_chapter = preferences->encoderPreferences.test_chapter;
	preferences->playerPreferences.test_position = preferences->encoderPreferences.test_position;

	QDialog::accept();
}

void PreferencesDialog::setControlValues()
{
	dvdIgnoreShortTitles->setChecked( preferences->playerPreferences.dvd_ignore_short_titles );
	dvdTitleMinLengthEdit->setText( QString::number(preferences->playerPreferences.dvd_title_min_length) );
	numTestFramesEdit->setText( QString::number(preferences->encoderPreferences.test_frames) );
	numTestChapterEdit->setText( QString::number(preferences->encoderPreferences.test_chapter) );
	numTestPositionEdit->setText( QString::number(preferences->encoderPreferences.test_position) );
	numFramesToValidEdit->setText( QString::number(preferences->encoderPreferences.validation_frames) );
	numSizeToValidEdit->setText( QString::number(preferences->encoderPreferences.validation_size) );
	forceOutputName->setChecked( preferences->encoderPreferences.force_output_name );
	outputNameEdit->setText( preferences->encoderPreferences.output_name );
	encLatencyStartEdit->setText( QString::number(preferences->encoderPreferences.latency_start) );
	encLatencyFinishedEdit->setText( QString::number(preferences->encoderPreferences.latency_finished) );
	encLatencyKillEdit->setText( QString::number(preferences->encoderPreferences.latency_kill) );
	playLatencyStartEdit->setText( QString::number(preferences->playerPreferences.latency_start) );
	playLatencyFinishedEdit->setText( QString::number(preferences->playerPreferences.latency_finished) );
	playLatencyKillEdit->setText( QString::number(preferences->playerPreferences.latency_kill) );
	playPollTicksEdit->setText( QString::number(preferences->playerPreferences.poll_ticks) );
}

void PreferencesDialog::resetPreferences()
{
	preferences->reset();

	setControlValues();
}

void PreferencesDialog::resetTimingPreferences()
{
	EncoderWidget::Preferences encoderPreferencesDefault;
	PlayerWidget::Preferences playerPreferencesDefault;

	preferences->encoderPreferences.latency_start = encoderPreferencesDefault.latency_start;
	preferences->encoderPreferences.latency_finished = encoderPreferencesDefault.latency_finished;
	preferences->encoderPreferences.latency_kill = encoderPreferencesDefault.latency_kill;

	preferences->playerPreferences.latency_start = playerPreferencesDefault.latency_start;
	preferences->playerPreferences.latency_finished = playerPreferencesDefault.latency_finished;
	preferences->playerPreferences.latency_kill = playerPreferencesDefault.latency_kill;
	preferences->playerPreferences.poll_ticks = playerPreferencesDefault.poll_ticks;

	setControlValues();
}
