/*
 * 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 "FitModifierWidget.h"
#include "FitModifier.h"

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

FitModifierWidget::FitModifierWidget(QWidget *parent)
: QWidget(parent)
{
	setWindowTitle(tr("Data File"));
	setWhatsThis(tr("fit {index &lt;index list&gt;}<br>"
				"{every &lt;every list&gt;}<br>"
				"{using &lt;using list&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;
	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;
	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;
	connect(dataSetIncCheckBox, SIGNAL(toggled(bool)),
			dataSetIncSpinBox, SLOT(setEnabled(bool)));

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

	pointIncSpinBox = new QSpinBox;
	connect(pointIncCheckBox, SIGNAL(toggled(bool)),
			pointIncSpinBox, SLOT(setEnabled(bool)));

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

	lineIncSpinBox = new QSpinBox;
	connect(lineIncCheckBox, SIGNAL(toggled(bool)),
			lineIncSpinBox, SLOT(setEnabled(bool)));

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

	startPointSpinBox = new QSpinBox;
	connect(startPointCheckBox, SIGNAL(toggled(bool)),
			startPointSpinBox, SLOT(setEnabled(bool)));

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

	startLineSpinBox = new QSpinBox;
	connect(startLineCheckBox, SIGNAL(toggled(bool)),
			startLineSpinBox, SLOT(setEnabled(bool)));

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

	endPointSpinBox = new QSpinBox;
	connect(endPointCheckBox, SIGNAL(toggled(bool)),
			endPointSpinBox, SLOT(setEnabled(bool)));

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

	endLineSpinBox = new QSpinBox;
	connect(endLineCheckBox, SIGNAL(toggled(bool)),
			endLineSpinBox, SLOT(setEnabled(bool)));

	// 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("fit {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("fit {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("fit {using &lt;using list&gt;}"));
	colFormatWidget->setLayout(colFormatLayout);

	QTabWidget *modTabWidget = new QTabWidget;
	modTabWidget->addTab(dataSetWidget, tr("&Indexes"));
	modTabWidget->addTab(periodWidget, tr("&Sampling"));
	modTabWidget->addTab(colFormatWidget, tr("C&olumns"));

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

	setLayout(mainLayout);
}

void FitModifierWidget::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 FitModifierWidget::setFitModifier(const FitModifier &fitModifier)
{
	int m = fitModifier.m();
	int n = fitModifier.n();
	int p = fitModifier.p();
	if (m < 0) {
		dataSetStartSpinBox->setEnabled(false);
		dataSetEndSpinBox->setEnabled(false);
		dataSetIncSpinBox->setEnabled(false);
	} else {
		dataSetStartCheckBox->setChecked(true);
		dataSetStartSpinBox->setValue(m);
		if (n < 0) {
			dataSetEndSpinBox->setEnabled(false);
			dataSetIncSpinBox->setEnabled(false);
		} else {
			dataSetEndCheckBox->setChecked(true);
			dataSetEndSpinBox->setValue(n);
			if (p < 0) {
				dataSetIncSpinBox->setEnabled(false);
			} else {
				dataSetIncCheckBox->setChecked(true);
				dataSetIncSpinBox->setValue(p);
			}
		}
	}
	int num = fitModifier.pointIncrement();
	if (num < 0) {
		pointIncSpinBox->setEnabled(false);
	} else {
		pointIncCheckBox->setChecked(true);
		pointIncSpinBox->setValue(num);
	}
	num = fitModifier.blockIncrement();
	if (num < 0) {
		lineIncSpinBox->setEnabled(false);
	} else {
		lineIncCheckBox->setChecked(true);
		lineIncSpinBox->setValue(num);
	}
	num = fitModifier.startPoint();
	if (num < 0) {
		startPointSpinBox->setEnabled(false);
	} else {
		startPointCheckBox->setChecked(true);
		startPointSpinBox->setValue(num);
	}
	num = fitModifier.startBlock();
	if (num < 0) {
		startLineSpinBox->setEnabled(false);
	} else {
		startLineCheckBox->setChecked(true);
		startLineSpinBox->setValue(num);
	}
	num = fitModifier.endPoint();
	if (num < 0) {
		endPointSpinBox->setEnabled(false);
	} else {
		endPointCheckBox->setChecked(true);
		endPointSpinBox->setValue(num);
	}
	num = fitModifier.endBlock();
	if (num < 0) {
		endLineSpinBox->setEnabled(false);
	} else {
		endLineCheckBox->setChecked(true);
		endLineSpinBox->setValue(num);
	}
	QStringList entry = fitModifier.entry();
	int size = entry.size();
	for (int i = 0; i < AXIS_NUM; i++) {
		columnLineEdit[i]->setText((size > i) ? entry[i] : "");
	}
	formatLineEdit->setText(fitModifier.format());
}

FitModifier FitModifierWidget::fitModifier() const
{
	FitModifier fitModifier;
	int m = -1, n = -1 , p = -1;
	if (dataSetStartCheckBox->isChecked()) {
		m = dataSetStartSpinBox->value();
		if (dataSetEndCheckBox->isChecked()) {
			n = dataSetEndSpinBox->value();
			if (dataSetIncCheckBox->isChecked()) {
				p = dataSetIncSpinBox->value();
			}
		}
	}
	fitModifier.setIndex(m, n, p);
	int num[6];
	if (!pointIncCheckBox->isChecked()) {
		num[0] = -1;
	} else {
		num[0] = pointIncSpinBox->value();
	}
	if (!lineIncCheckBox->isChecked()) {
		num[1] = -1;
	} else {
		num[1] = lineIncSpinBox->value();
	}
	if (!startPointCheckBox->isChecked()) {
		num[2] = -1;
	} else {
		num[2] = startPointSpinBox->value();
	}
	if (!startLineCheckBox->isChecked()) {
		num[3] = -1;
	} else {
		num[3] = startLineSpinBox->value();
	}
	if (!endPointCheckBox->isChecked()) {
		num[4] = -1;
	} else {
		num[4] = endPointSpinBox->value();
	}
	if (!endLineCheckBox->isChecked()) {
		num[5] = -1;
	} else {
		num[5] = endLineSpinBox->value();
	}
	fitModifier.setEvery(num[0], num[1], num[2], num[3],
			num[4], num[5]);

	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();
	fitModifier.setUsing(entry, format);

	return fitModifier;
}
