/*
 * 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 "PlotModifierWidget.h"
#include "PlotModifier.h"

#include <QtGui/QCheckBox>
#include <QtGui/QComboBox>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QGridLayout>
#include <QtGui/QSpinBox>
#include <QtGui/QVBoxLayout>

#include <limits> // max()

PlotModifierWidget::PlotModifierWidget(QWidget *parent)
: PlotOptionWidget(parent), plotModifier_(new PlotModifier)
{
	setWindowTitle(tr("Data File"));
	setWhatsThis(tr("plot {index &lt;index list&gt;}<br>"
				"{every &lt;every list&gt;}<br>"
				"{using &lt;using list&gt;}<br>"
				"{smooth &lt;option&gt;}"));

	const QString AXIS[] = { "&X", "&Y", "&Z" };
	QLabel *columnLabel[AXIS_NUM];
	for (int i = 0; i < AXIS_NUM; i++) {
		columnLineEdit[i] = new QLineEdit;

		columnLabel[i] = new QLabel;
		columnLabel[i]->setText(AXIS[i] + tr(" column:"));
		columnLabel[i]->setBuddy(columnLineEdit[i]);
	}

	formatLineEdit = new QLineEdit;

	QLabel *formatLabel = new QLabel;
	formatLabel->setText(tr("Fo&rmat:"));
	formatLabel->setBuddy(formatLineEdit);

	dataSetStartCheckBox = new QCheckBox;
	dataSetStartCheckBox->setText(tr("Specify a s&tarting index:"));
	connect(dataSetStartCheckBox, SIGNAL(toggled(bool)),
			this, SLOT(setIndex()));

	dataSetStartSpinBox = new QSpinBox;
	dataSetStartSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(dataSetStartCheckBox, SIGNAL(toggled(bool)),
			dataSetStartSpinBox, SLOT(setEnabled(bool)));

	dataSetEndCheckBox = new QCheckBox;
	dataSetEndCheckBox->setText(tr("Specify a &ending index:"));
	connect(dataSetEndCheckBox, SIGNAL(toggled(bool)),
			this, SLOT(setIndex()));

	dataSetEndSpinBox = new QSpinBox;
	dataSetEndSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(dataSetEndCheckBox, SIGNAL(toggled(bool)),
			dataSetEndSpinBox, SLOT(setEnabled(bool)));

	dataSetIncCheckBox = new QCheckBox;
	dataSetIncCheckBox->setText(tr("Specify i&ncrement of index:"));
	connect(dataSetIncCheckBox, SIGNAL(toggled(bool)),
			this, SLOT(setIndex()));

	dataSetIncSpinBox = new QSpinBox;
	dataSetIncSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(dataSetIncCheckBox, SIGNAL(toggled(bool)),
			dataSetIncSpinBox, SLOT(setEnabled(bool)));

	pointIncCheckBox = new QCheckBox;
	pointIncCheckBox->setText(tr("Specify &point increment:"));

	pointIncSpinBox = new QSpinBox;
	pointIncSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(pointIncCheckBox, SIGNAL(toggled(bool)),
			pointIncSpinBox, SLOT(setEnabled(bool)));

	lineIncCheckBox = new QCheckBox;
	lineIncCheckBox->setText(tr("Specify li&ne increment:"));

	lineIncSpinBox = new QSpinBox;
	lineIncSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(lineIncCheckBox, SIGNAL(toggled(bool)),
			lineIncSpinBox, SLOT(setEnabled(bool)));

	startPointCheckBox = new QCheckBox;
	startPointCheckBox->setText(tr("Specify a s&tart point:"));

	startPointSpinBox = new QSpinBox;
	startPointSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(startPointCheckBox, SIGNAL(toggled(bool)),
			startPointSpinBox, SLOT(setEnabled(bool)));

	startLineCheckBox = new QCheckBox;
	startLineCheckBox->setText(tr("Specify a sta&rt line:"));

	startLineSpinBox = new QSpinBox;
	startLineSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(startLineCheckBox, SIGNAL(toggled(bool)),
			startLineSpinBox, SLOT(setEnabled(bool)));

	endPointCheckBox = new QCheckBox;
	endPointCheckBox->setText(tr("Specify a &end point:"));

	endPointSpinBox = new QSpinBox;
	endPointSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(endPointCheckBox, SIGNAL(toggled(bool)),
			endPointSpinBox, SLOT(setEnabled(bool)));

	endLineCheckBox = new QCheckBox;
	endLineCheckBox->setText(tr("Specify a en&d line:"));

	endLineSpinBox = new QSpinBox;
	endLineSpinBox->setMaximum(std::numeric_limits<int>::max());
	connect(endLineCheckBox, SIGNAL(toggled(bool)),
			endLineSpinBox, SLOT(setEnabled(bool)));

	interpCheckBox = new QCheckBox;
	interpCheckBox->setText(tr("S&pecify:"));

	interpComboBox = new QComboBox;
	for (int i = 0; !PlotModifier::SMOOTH[i].isEmpty(); i++) {
		interpComboBox->addItem(PlotModifier::SMOOTH[i]);
	}
	connect(interpCheckBox, SIGNAL(toggled(bool)),
			interpComboBox, SLOT(setEnabled(bool)));

	// create layouts
	// assemble layouts and widgets

	QGridLayout *dataSetLayout = new QGridLayout;
	dataSetLayout->addWidget(dataSetStartCheckBox, 0, 0);
	dataSetLayout->addWidget(dataSetStartSpinBox, 0, 1);
	dataSetLayout->addItem(new QSpacerItem(40, 20, 
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);
	dataSetLayout->addWidget(dataSetEndCheckBox, 1, 0);
	dataSetLayout->addWidget(dataSetEndSpinBox, 1, 1);
	dataSetLayout->addWidget(dataSetIncCheckBox, 2, 0);
	dataSetLayout->addWidget(dataSetIncSpinBox, 2, 1);
	dataSetLayout->addItem(new QSpacerItem(20, 40,
				QSizePolicy::Minimum, QSizePolicy::Expanding), 3, 0);

	QWidget *dataSetWidget = new QWidget;
	dataSetWidget->setWhatsThis(tr("plot {index &lt;index list&gt;}"));
	dataSetWidget->setLayout(dataSetLayout);

	QGridLayout *periodLayout = new QGridLayout;
	periodLayout->addWidget(pointIncCheckBox, 0, 0);
	periodLayout->addWidget(pointIncSpinBox, 0, 1);
	periodLayout->addItem(new QSpacerItem(40, 20,
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);
	periodLayout->addWidget(startPointCheckBox, 1, 0);
	periodLayout->addWidget(startPointSpinBox, 1, 1);
	periodLayout->addWidget(endPointCheckBox, 2, 0);
	periodLayout->addWidget(endPointSpinBox, 2, 1);
	periodLayout->addWidget(lineIncCheckBox, 3, 0);
	periodLayout->addWidget(lineIncSpinBox, 3, 1);
	periodLayout->addWidget(startLineCheckBox, 4, 0);
	periodLayout->addWidget(startLineSpinBox, 4, 1);
	periodLayout->addWidget(endLineCheckBox, 5, 0);
	periodLayout->addWidget(endLineSpinBox, 5, 1);
	periodLayout->addItem(new QSpacerItem(20, 40,
				QSizePolicy::Minimum, QSizePolicy::Expanding), 6, 0);

	QWidget *periodWidget = new QWidget;
	periodWidget->setWhatsThis(tr("plot {every &lt;every list&gt;}"));
	periodWidget->setLayout(periodLayout);

	QGridLayout *colFormatLayout = new QGridLayout;
	for (int i = 0; i < AXIS_NUM; i++) {
		colFormatLayout->addWidget(columnLabel[i], i, 0);
		colFormatLayout->addWidget(columnLineEdit[i], i, 1);
	}
	colFormatLayout->addItem(new QSpacerItem(40, 20,
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);
	colFormatLayout->addWidget(formatLabel, 3, 0);
	colFormatLayout->addWidget(formatLineEdit, 3, 1, 1, 2);
	colFormatLayout->addItem(new QSpacerItem(20, 40,
				QSizePolicy::Minimum, QSizePolicy::Expanding), 4, 0);

	QWidget *colFormatWidget = new QWidget;
	colFormatWidget->setWhatsThis(tr("plot {using &lt;using list&gt;}"));
	colFormatWidget->setLayout(colFormatLayout);

	QGridLayout *interpLayout = new QGridLayout;
	interpLayout->addWidget(interpCheckBox, 0, 0);
	interpLayout->addWidget(interpComboBox, 0, 1);
	interpLayout->addItem(new QSpacerItem(40, 20,
				QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2);
	interpLayout->addItem(new QSpacerItem(20, 40,
				QSizePolicy::Minimum, QSizePolicy::Expanding), 1, 0);

	QWidget *interpWidget = new QWidget;
	interpWidget->setWhatsThis(tr("plot {smooth &lt;option&gt;}"));
	interpWidget->setLayout(interpLayout);

	QTabWidget *modTabWidget = new QTabWidget;
	modTabWidget->addTab(dataSetWidget, tr("&Indexes"));
	modTabWidget->addTab(periodWidget, tr("&Sampling"));
	modTabWidget->addTab(colFormatWidget, tr("Co&lumns"));
	modTabWidget->addTab(interpWidget, tr("S&moothing"));

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(modTabWidget);

	setLayout(mainLayout);
}

PlotModifierWidget::~PlotModifierWidget()
{
	delete plotModifier_;
}

void PlotModifierWidget::setIndex()
{
	bool hasStart = dataSetStartCheckBox->isChecked();
	dataSetEndCheckBox->setEnabled(hasStart);
	dataSetEndSpinBox->setEnabled(hasStart 
			&& dataSetEndCheckBox->isChecked());

	bool hasEnd = dataSetEndCheckBox->isChecked();
	dataSetIncCheckBox->setEnabled(hasStart && hasEnd);
	dataSetIncSpinBox->setEnabled(hasStart && hasEnd
			&& dataSetIncCheckBox->isChecked());
}

void PlotModifierWidget::setPlotModifier(const PlotModifier &plotModifier)
{
	*plotModifier_ = plotModifier;
	setWidget();
}

const PlotModifier &PlotModifierWidget::plotModifier() const
{
	return *plotModifier_;
}

void PlotModifierWidget::apply()
{
	int m = dataSetStartCheckBox->isChecked() ? 
		dataSetStartSpinBox->value() : -1;
	int n = dataSetEndCheckBox->isChecked() ?
		dataSetEndSpinBox->value() : -1;
	int p = dataSetIncCheckBox->isChecked() ?
		dataSetIncSpinBox->value() : -1;
	plotModifier_->setIndex(m, n, p);

	int num[6];
	num[0] = pointIncCheckBox->isChecked() ? pointIncSpinBox->value() : -1;
	num[1] = lineIncCheckBox->isChecked() ? lineIncSpinBox->value() : -1;
	num[2] = startPointCheckBox->isChecked() ? startPointSpinBox->value() : -1;
	num[3] = startLineCheckBox->isChecked() ? startLineSpinBox->value() : -1;
	num[4] = endPointCheckBox->isChecked() ? endPointSpinBox->value() : -1;
	num[5] = endLineCheckBox->isChecked() ? endLineSpinBox->value() : -1;
	plotModifier_->setEvery(num[0], num[1], num[2], num[3],
			num[4], num[5]);

	plotModifier_->setSmooth(interpCheckBox->isChecked() ? 
			interpComboBox->currentIndex() : -1);

	QStringList entry;
	for (int i = 0; i < AXIS_NUM; i++) {
		QString text = columnLineEdit[i]->text();
		if (text.isEmpty()) {
			break;
		} else {
			entry << text;
		}
	}
	QString format = formatLineEdit->text();
	plotModifier_->setUsing(entry, format);
}

void PlotModifierWidget::setWidget()
{
	int m = plotModifier_->m();
	bool hasStart = (m >= 0);
	if (hasStart) {
		dataSetStartSpinBox->setValue(m);
	}
	dataSetStartCheckBox->setChecked(hasStart);
	dataSetStartSpinBox->setEnabled(hasStart);

	int n = plotModifier_->n();
	bool hasEnd = (n >= 0);
	if (hasEnd) {
		dataSetEndSpinBox->setValue(n);
	}
	bool hasStartEnd = hasStart && hasEnd;
	dataSetEndCheckBox->setEnabled(hasStart);
	dataSetEndCheckBox->setChecked(hasStartEnd);
	dataSetEndSpinBox->setEnabled(hasStartEnd);

	int p = plotModifier_->p();
	bool hasInc = (p >= 0);
	if (hasInc) {
		dataSetIncSpinBox->setValue(p);
	}
	bool hasStartEndInc = hasStartEnd && hasStartEnd;
	dataSetIncCheckBox->setEnabled(hasStartEnd);
	dataSetIncCheckBox->setChecked(hasStartEndInc);
	dataSetIncSpinBox->setEnabled(hasStartEndInc);

	int num = plotModifier_->pointIncrement();
	bool isPos = (num >= 0);
	if (isPos) {
		pointIncSpinBox->setValue(num);
	}
	pointIncCheckBox->setChecked(isPos);
	pointIncSpinBox->setEnabled(isPos);

	num = plotModifier_->blockIncrement();
	isPos = (num >= 0);
	if (isPos) {
		lineIncSpinBox->setValue(num);
	}
	lineIncCheckBox->setChecked(isPos);
	lineIncSpinBox->setEnabled(isPos);

	num = plotModifier_->startPoint();
	isPos = (num >= 0);
	if (isPos) {
		startPointSpinBox->setValue(num);
	}
	startPointCheckBox->setChecked(isPos);
	startPointSpinBox->setEnabled(isPos);

	num = plotModifier_->startBlock();
	isPos = (num >= 0);
	if (isPos) {
		startLineSpinBox->setValue(num);
	}
	startLineCheckBox->setChecked(isPos);
	startLineSpinBox->setEnabled(isPos);

	num = plotModifier_->endPoint();
	isPos = (num >= 0);
	if (isPos) {
		endPointSpinBox->setValue(num);
	}
	endPointCheckBox->setChecked(isPos);
	endPointSpinBox->setEnabled(isPos);

	num = plotModifier_->endBlock();
	isPos = (num >= 0);
	if (isPos) {
		endLineSpinBox->setValue(num);
	}
	endLineCheckBox->setChecked(isPos);
	endLineSpinBox->setEnabled(isPos);

	int smooth = plotModifier_->smooth();
	isPos = (smooth >= 0);
	if (isPos) {
		interpComboBox->setCurrentIndex(smooth);
	}
	interpCheckBox->setChecked(isPos);
	interpComboBox->setEnabled(isPos);

	QStringList entry = plotModifier_->entry();
	int size = entry.size();
	for (int i = 0; i < AXIS_NUM; i++) {
		columnLineEdit[i]->setText((size > i) ? entry[i] : "");
	}
	formatLineEdit->setText(plotModifier_->format());
}
