/*
 * Cueplot: a GUI front-end to gnuplot
 * Copyright (C) 2007, 2008 Muneyuki Noguchi
 *
 * 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 "KeyOptionWidget.h"
#include "Key.h"

#include <QtCore/QCoreApplication>
#include <QtGui/QCheckBox>
#include <QtGui/QComboBox>
#include <QtGui/QDoubleSpinBox>
#include <QtGui/QGridLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QRadioButton>
#include <QtGui/QSpinBox>
#include <QtGui/QStackedWidget>
#include <QtGui/QTabWidget>
#include <QtGui/QVBoxLayout>

#include <cmath> // pow()
#include <limits> // max()

KeyOptionWidget::KeyOptionWidget(QWidget *parent)
: OptionWidget(parent), key(0)
{
	setWindowTitle(tr("Legend"));
}

KeyOptionWidget::~KeyOptionWidget()
{
	while (!positionCheckBoxList.isEmpty()) {
		delete positionCheckBoxList.takeFirst();
	}
	while (!positionDoubleSpinBoxList.isEmpty()) {
		delete positionDoubleSpinBoxList.takeFirst();
	}
	delete key;
}

void KeyOptionWidget::construct()
{
	setWhatsThis("set key");

	keyCheckBox = new QCheckBox;
	keyCheckBox->setText(tr("Ac&tivation"));
	connect(keyCheckBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	for (int i = 0; Key::POSITION[i][0]; i++) {
		QCheckBox *positionCheckBox = new QCheckBox;
		positionCheckBox->setText(QCoreApplication::translate(
					"Key", Key::POSITION[i]));
		connect(positionCheckBox, SIGNAL(toggled(bool)),
				this, SIGNAL(modified()));
		positionCheckBoxList.append(positionCheckBox);
	}

	const int num = 3;
	QGridLayout *cornerLayout = new QGridLayout;
	for (int i = 0; Key::POSITION[i][0]; i++) {
		cornerLayout->addWidget(positionCheckBoxList[i], i / num, i % num);
	}
	cornerLayout->addItem(new QSpacerItem(40, 20, 
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, num);

	QWidget *cornerWidget = new QWidget;
	cornerWidget->setLayout(cornerLayout);

	for (int i = 0; !Key::AXIS[i].isEmpty(); i++) {
		QDoubleSpinBox *positionDoubleSpinBox = new QDoubleSpinBox;
		positionDoubleSpinBox->setMaximum(std::numeric_limits<double>::max());
		positionDoubleSpinBox->setMinimum(-std::numeric_limits<double>::max());
		connect(positionDoubleSpinBox, SIGNAL(valueChanged(double)),
				this, SIGNAL(modified()));
		positionDoubleSpinBoxList.append(positionDoubleSpinBox);
	}

	QGridLayout *coordinateLayout = new QGridLayout;
	for (int i = 0; !Key::AXIS[i].isEmpty(); i++) {
		QLabel *positionLabel = new QLabel;
		positionLabel->setText(Key::AXIS[i] + ":");
		positionLabel->setBuddy(positionDoubleSpinBoxList[i]);

		coordinateLayout->addWidget(positionLabel, i, 0);
		coordinateLayout->addWidget(positionDoubleSpinBoxList[i], i, 1);
	}
	coordinateLayout->addItem(new QSpacerItem(40, 20, 
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);

	QWidget *coordinateWidget = new QWidget;
	coordinateWidget->setLayout(coordinateLayout);

	QStackedWidget *positionStackedWidget = new QStackedWidget;
	positionStackedWidget->addWidget(cornerWidget);
	positionStackedWidget->addWidget(coordinateWidget);

	positionComboBox = new QComboBox;
	positionComboBox->addItem(tr("Corner"));
	positionComboBox->addItem(tr("Coordinate"));
	connect(positionComboBox, SIGNAL(activated(int)),
			positionStackedWidget, SLOT(setCurrentIndex(int)));
	connect(positionComboBox, SIGNAL(activated(int)),
			this, SIGNAL(modified()));

	textJustifyCheckBox = new QCheckBox;
	textJustifyCheckBox->setText(tr("&Left justify"));
	connect(textJustifyCheckBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	reverseCheckBox = new QCheckBox;
	reverseCheckBox->setText(tr("&Reverse"));
	connect(reverseCheckBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	autoTitlesCheckBox = new QCheckBox;
	autoTitlesCheckBox->setText(tr("A&uto titles"));
	connect(autoTitlesCheckBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	enhancedCheckBox = new QCheckBox;
	enhancedCheckBox->setText(tr("&Enhanced"));
	connect(enhancedCheckBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	sampleLengthDoubleSpinBox = new QDoubleSpinBox;
	connect(sampleLengthDoubleSpinBox, SIGNAL(valueChanged(double)),
			this, SIGNAL(modified()));

	QLabel *sampleLengthLabel = new QLabel;
	sampleLengthLabel->setText(tr("&Sample length:"));
	sampleLengthLabel->setBuddy(sampleLengthDoubleSpinBox);

	spacingDoubleSpinBox = new QDoubleSpinBox;
	connect(spacingDoubleSpinBox, SIGNAL(valueChanged(double)),
			this, SIGNAL(modified()));

	QLabel *spacingLabel = new QLabel;
	spacingLabel->setText(tr("Spac&ing:"));
	spacingLabel->setBuddy(spacingDoubleSpinBox);

	widthIncrementDoubleSpinBox = new QDoubleSpinBox;
	widthIncrementDoubleSpinBox->setMinimum(-99);
	connect(widthIncrementDoubleSpinBox, SIGNAL(valueChanged(double)),
			this, SIGNAL(modified()));

	QLabel *widthIncrementLabel = new QLabel;
	widthIncrementLabel->setText(tr("&Width increment:"));
	widthIncrementLabel->setBuddy(widthIncrementDoubleSpinBox);

	heightIncrementDoubleSpinBox = new QDoubleSpinBox;
	heightIncrementDoubleSpinBox->setMinimum(-99);
	connect(heightIncrementDoubleSpinBox, SIGNAL(valueChanged(double)),
			this, SIGNAL(modified()));

	QLabel *heightIncrementLabel = new QLabel;
	heightIncrementLabel->setText(tr("Hei&ght Increment:"));
	heightIncrementLabel->setBuddy(heightIncrementDoubleSpinBox);

	legendTitleLineEdit = new QLineEdit;
	connect(legendTitleLineEdit, SIGNAL(textChanged(const QString &)),
			this, SIGNAL(modified()));

	QLabel *legendTitleLabel = new QLabel;
	legendTitleLabel->setText(tr("Leg&end title:"));
	legendTitleLabel->setBuddy(legendTitleLineEdit);

	lineTypeSpinBox = new QSpinBox;
	connect(lineTypeSpinBox, SIGNAL(valueChanged(int)),
			this, SIGNAL(modified()));

	lineTypeLabel = new QLabel;
	lineTypeLabel->setText(tr("&Line type:"));
	lineTypeLabel->setBuddy(lineTypeSpinBox);

	lineWidthDoubleSpinBox = new QDoubleSpinBox;
	connect(lineWidthDoubleSpinBox, SIGNAL(valueChanged(double)),
			this, SIGNAL(modified()));

	lineWidthLabel = new QLabel;
	lineWidthLabel->setText(tr("L&ine width:"));
	lineWidthLabel->setBuddy(lineWidthDoubleSpinBox);

	QVBoxLayout *positionLayout = new QVBoxLayout;
	positionLayout->addWidget(positionComboBox);
	positionLayout->addWidget(positionStackedWidget);
	positionLayout->addStretch();

	QWidget *positionWidget = new QWidget;
	positionWidget->setLayout(positionLayout);

	QGridLayout *boxLayout = new QGridLayout;
	boxLayout->addWidget(lineTypeLabel, 0, 0);
	boxLayout->addWidget(lineTypeSpinBox, 0, 1);
	boxLayout->addItem(new QSpacerItem(40, 20, 
					QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);
	boxLayout->addWidget(lineWidthLabel, 1, 0);
	boxLayout->addWidget(lineWidthDoubleSpinBox, 1, 1);

	boxGroupBox = new QGroupBox(tr("Bo&x"));
	boxGroupBox->setCheckable(true);
	boxGroupBox->setLayout(boxLayout);
	connect(boxGroupBox, SIGNAL(toggled(bool)),
			lineTypeLabel, SLOT(setEnabled(bool)));
	connect(boxGroupBox, SIGNAL(toggled(bool)),
			lineTypeSpinBox, SLOT(setEnabled(bool)));
	connect(boxGroupBox, SIGNAL(toggled(bool)),
			lineWidthLabel, SLOT(setEnabled(bool)));
	connect(boxGroupBox, SIGNAL(toggled(bool)),
			lineWidthDoubleSpinBox, SLOT(setEnabled(bool)));
	connect(boxGroupBox, SIGNAL(toggled(bool)),
			this, SIGNAL(modified()));

	QHBoxLayout *titleLayout = new QHBoxLayout;
	titleLayout->addWidget(legendTitleLabel);
	titleLayout->addWidget(legendTitleLineEdit);

	QVBoxLayout *boxTabLayout = new QVBoxLayout;
	boxTabLayout->addWidget(boxGroupBox);
	boxTabLayout->addLayout(titleLayout);
	boxTabLayout->addStretch();

	QWidget *boxWidget = new QWidget;
	boxWidget->setLayout(boxTabLayout);

	QGridLayout *othersLayout = new QGridLayout;
	othersLayout->addWidget(textJustifyCheckBox, 0, 0);
	othersLayout->addWidget(reverseCheckBox, 0, 1);
	othersLayout->addWidget(autoTitlesCheckBox, 1, 0);
	othersLayout->addWidget(enhancedCheckBox, 1, 1);
	othersLayout->addWidget(sampleLengthLabel, 2, 0);
	othersLayout->addWidget(sampleLengthDoubleSpinBox, 2, 1);
	othersLayout->addItem(new QSpacerItem(40, 20, 
				QSizePolicy::Expanding, QSizePolicy::Minimum), 2, 2);
	othersLayout->addWidget(spacingLabel, 3, 0);
	othersLayout->addWidget(spacingDoubleSpinBox, 3, 1);
	othersLayout->addWidget(widthIncrementLabel, 4, 0);
	othersLayout->addWidget(widthIncrementDoubleSpinBox, 4, 1);
	othersLayout->addWidget(heightIncrementLabel, 5, 0);
	othersLayout->addWidget(heightIncrementDoubleSpinBox, 5, 1);
	othersLayout->addItem(new QSpacerItem(20, 40,
				QSizePolicy::Minimum, QSizePolicy::Expanding), 7, 0);

	QWidget *othersWidget = new QWidget;
	othersWidget->setLayout(othersLayout);

	QTabWidget *tabWidget = new QTabWidget;
	tabWidget->addTab(positionWidget, tr("&Position"));
	tabWidget->addTab(boxWidget, tr("&Box and Title"));
	tabWidget->addTab(othersWidget, tr("Ot&hers"));
	connect(keyCheckBox, SIGNAL(toggled(bool)), 
			tabWidget, SLOT(setEnabled(bool)));

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(keyCheckBox);
	mainLayout->addWidget(tabWidget);

	setLayout(mainLayout);
}

void KeyOptionWidget::init()
{
	delete key;
	key = new Key;
	setWidget();
}

void KeyOptionWidget::apply()
{
	key->setOn(keyCheckBox->isChecked());

	switch (positionComboBox->currentIndex()) {
	case 0:
		{
			int pos = 0;
			for (int i = 0; Key::POSITION[i][0]; i++) {
				if (positionCheckBoxList.at(i)->isChecked()) {
					pos |= static_cast<int>(
							std::pow(static_cast<double>(2), i));
				}
			}
			key->setPosition(pos);
		}
		break;
	case 1:
		for (int i = 0; !Key::AXIS[i].isEmpty(); i++) {
			key->setPosition(i, positionDoubleSpinBoxList.at(i)->value());
		}
	}

	key->setLeftJustification(textJustifyCheckBox->isChecked());
	key->setReverse(reverseCheckBox->isChecked());
	key->setSampleLength(sampleLengthDoubleSpinBox->value());
	key->setVerticalSpacing(spacingDoubleSpinBox->value());
	key->setWidthIncrement(widthIncrementDoubleSpinBox->value());
	key->setHeightIncrement(heightIncrementDoubleSpinBox->value());
	key->setAutoTitles(autoTitlesCheckBox->isChecked());
	key->setTitle(legendTitleLineEdit->text());
	key->setEnhanced(enhancedCheckBox->isChecked());
	key->setBox(boxGroupBox->isChecked());
	if (boxGroupBox->isChecked()) {
		key->setLineType(lineTypeSpinBox->value());
		key->setLineWidth(lineWidthDoubleSpinBox->value());
	}

	emit executed(key->command());
}

void KeyOptionWidget::setWidget()
{
	keyCheckBox->setChecked(key->isOn());

	int pos = key->position();
	positionComboBox->setCurrentIndex(pos == 0);
	for (int i = 0; Key::POSITION[i][0]; i++) {
		positionCheckBoxList[i]->setChecked(pos 
				& static_cast<int>(std::pow(static_cast<double>(2), i)));
	}
	for (int i = 0; !Key::AXIS[i].isEmpty(); i++) {
		positionDoubleSpinBoxList[i]->setValue(key->position(i));
	}

	textJustifyCheckBox->setChecked(key->leftJustification());
	reverseCheckBox->setChecked(key->isReverse());
	sampleLengthDoubleSpinBox->setValue(key->sampleLength());
	spacingDoubleSpinBox->setValue(key->verticalSpacing());
	widthIncrementDoubleSpinBox->setValue(key->widthIncrement());
	heightIncrementDoubleSpinBox->setValue(key->heightIncrement());
	autoTitlesCheckBox->setChecked(key->isAutoTitles());
	legendTitleLineEdit->setText(key->title());
	enhancedCheckBox->setChecked(key->enhances());

	boxGroupBox->setChecked(key->isBox());
	if (key->isBox()) {
		lineTypeSpinBox->setValue(key->lineType());
		lineWidthDoubleSpinBox->setValue(key->lineWidth());
	} else {
		lineTypeSpinBox->setEnabled(false);
		lineTypeLabel->setEnabled(false);
		lineWidthDoubleSpinBox->setEnabled(false);
		lineWidthLabel->setEnabled(false);
	}
}
