/*
 * 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 "PlotDataWidget.h"
#include "Plot.h"
#include "PlotListModel.h"
#include "PlotListView.h"
#include "PlotOptionDialog.h"

#include <QtGui/QListWidget>
#include <QtGui/QGridLayout>
#include <QtGui/QPushButton>

PlotDataWidget::PlotDataWidget(QWidget *parent)
: QWidget(parent)
{
	addPushButton = new QPushButton;
	addPushButton->setText(tr("&Add"));
	addPushButton->setEnabled(false);
	connect(addPushButton, SIGNAL(clicked()),
			this, SIGNAL(dataAdded()));

	optionPushButton = new QPushButton;
	optionPushButton->setText(tr("O&ption..."));
	optionPushButton->setEnabled(false);
	optionPushButton->setSizePolicy(
			QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
	connect(optionPushButton, SIGNAL(clicked()),
			this, SLOT(setPlotOptions()));

	upPushButton = new QPushButton;
	upPushButton->setText(tr("&Up"));
	upPushButton->setEnabled(false);
	connect(upPushButton, SIGNAL(clicked()),
			this, SLOT(setDataUp()));

	downPushButton = new QPushButton;
	downPushButton->setText(tr("&Down"));
	downPushButton->setEnabled(false);
	connect(downPushButton, SIGNAL(clicked()),
			this, SLOT(setDataDown()));

	deletePushButton = new QPushButton;
	deletePushButton->setText(tr("D&elete"));
	deletePushButton->setEnabled(false);
	deletePushButton->setSizePolicy(
			QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
	connect(deletePushButton, SIGNAL(clicked()),
			this, SLOT(deleteData()));

	plotListModel = new PlotListModel;

	plotListView = new PlotListView;
	plotListView->setModel(plotListModel);
	plotListView->setAcceptDrops(true);
	plotListView->setDropIndicatorShown(true);
	connect(plotListModel, 
			SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
			this, SLOT(changeDialog(const QModelIndex &, const QModelIndex &)));
	connect(plotListModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
			this, SLOT(insertDialog(const QModelIndex &, int, int)));
	connect(plotListModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
			this, SLOT(removeDialog(const QModelIndex &, int, int)));

	selectionModel = plotListView->selectionModel();
	connect(selectionModel,
			SIGNAL(selectionChanged(const QItemSelection &,
					const QItemSelection &)), this, SLOT(setPushButton()));

	// ----------- assemble layouts and widgets
	// ------------------------ create layouts

	QGridLayout *mainLayout = new QGridLayout;
	mainLayout->setMargin(0);
	mainLayout->addWidget(addPushButton, 0, 0);
	mainLayout->addWidget(optionPushButton, 1, 0);
	mainLayout->addWidget(upPushButton, 2, 0);
	mainLayout->addWidget(downPushButton, 3, 0);
	// ウィンドウを最大化したときのことを考えて、QSpacerItem を入れる
	mainLayout->addItem(new QSpacerItem(20, 0, 
				QSizePolicy::Minimum, QSizePolicy::Expanding), 4, 0);
	mainLayout->addItem(new QSpacerItem(40, 20, 
				QSizePolicy::Expanding, QSizePolicy::Minimum), 5, 0, 1, 2);
	mainLayout->addWidget(deletePushButton, 5, 2);
	mainLayout->addWidget(plotListView, 0, 1, 5, 2);

	setLayout(mainLayout);
}

void PlotDataWidget::addData(const Plot &plot)
{
	// 挿入する場所
	int row = (selectionModel->selectedIndexes().size()) ?
		selectionModel->selectedIndexes()[0].row() + 1 
		: plotListModel->rowCount();

	// 項目を挿入する
	plotListModel->insertRow(row);

	// 項目を設定する
	plotListModel->setPlot(plotListModel->index(row), plot);
}

void PlotDataWidget::setDataUp()
{
	swapData(true);
}

void PlotDataWidget::setDataDown()
{
	swapData(false);
}

void PlotDataWidget::swapData(bool up)
{
	QModelIndexList list = selectionModel->selectedIndexes();
	if (!list.size()) {
		return;
	}
	int row = list[0].row();
	// 一番{上|下}にある項目はこれ以上、{上|下}に動かせない
	if ((up && row > 0) || (!up && (row < plotListModel->rowCount() - 1))) {
		plotListModel->swapRow(up ? row -1 : row, up ? row : row + 1);
		// 動かした項目を選択状態にする
		selectionModel->clear();
		int idx = up ? row -1 : row + 1;
		QModelIndex modelIndex = plotListModel->index(idx); 
		selectionModel->select(modelIndex, QItemSelectionModel::Select);
		selectionModel->setCurrentIndex(modelIndex, 
				QItemSelectionModel::Select);

		dialogList.swap(row, idx);
	}
}

void PlotDataWidget::deleteData()
{
	QModelIndexList list = selectionModel->selectedIndexes();
	if (!list.size()) {
		return;
	}
	int row = list[0].row();
	plotListModel->removeRow(row);
}

void PlotDataWidget::setPushButton()
{
	// 項目が一つでも選択されていたら、
	// オプションボタンと削除ボタンを有効にする
	QModelIndexList list = selectionModel->selectedIndexes();
	bool isSelected = list.size();
	optionPushButton->setEnabled(isSelected);
	deletePushButton->setEnabled(isSelected);

	// 選択された項目があり、複数の項目がリスト中にあれば、
	// 上ボタンと下ボタンを有効にする
	int count = plotListModel->rowCount();
	bool isMulti = isSelected && (count > 1);
	// 選択された項目が一番上にあるときは上ボタンを無効にする
	upPushButton->setEnabled(isMulti && !(list[0].row() == 0));
	// 選択された項目が一番下にあるときは下ボタンを無効にする
	downPushButton->setEnabled(isMulti && !(list[0].row() == count - 1));
}

void PlotDataWidget::changeOption(const PlotOptionDialog &dialog,
		const Plot &plot)
{
	// オプションを変えたダイアログをリストの中から探す
	int idx = -1;
	for (int i = 0, j = dialogList.size(); i < j; i++) {
		const PlotOptionDialog *d = dialogList.at(i);
		if (d == &dialog) {
			idx = i;
			break;
		}
	}
	if (idx >= 0) {
		// オプションの変更を適用する
		plotListModel->setPlot(plotListModel->index(idx), plot);
	}
}

void PlotDataWidget::setAdditionEnabled(bool enable)
{
	addPushButton->setEnabled(enable);
}

void PlotDataWidget::setPlotOptions()
{
	QModelIndexList list = selectionModel->selectedIndexes();
	if (!list.size()) {
		return;
	}
	int row = list[0].row();
	PlotOptionDialog *plotOptionDialog = dialogList.at(row);
	// 初めてダイアログを開くとき
	if (!plotOptionDialog) {
		plotOptionDialog = new PlotOptionDialog;
		plotOptionDialog->setPlot(plotListModel->plot(list[0]));
		dialogList[row] = plotOptionDialog;
		connect(plotOptionDialog, 
				SIGNAL(optionChanged(const PlotOptionDialog &, const Plot &)),
				this,
				SLOT(changeOption(const PlotOptionDialog &, const Plot &)));
	}
	plotOptionDialog->show();
	plotOptionDialog->raise();
	plotOptionDialog->activateWindow();
}

void PlotDataWidget::changeDialog(const QModelIndex &topLeft, 
		const QModelIndex &bottomRight)
{
	for (int i = topLeft.row(), j = bottomRight.row(); i <= j; i++) {
		PlotOptionDialog *plotOptionDialog = dialogList.at(i);
		if (plotOptionDialog) {
			plotOptionDialog->setPlot(
					plotListModel->plot(plotListModel->index(i)));
		}
	}
	setAction();
}

void PlotDataWidget::insertDialog(const QModelIndex &/*parent*/,
		int start, int end)
{
	for (int i = start; i <= end; i++) {
		dialogList.insert(i, 0);
	}
	// 挿入した項目のうち最後の項目を選択状態にする
	QModelIndex modelIndex = plotListModel->index(end);
	selectionModel->clear();
	selectionModel->select(modelIndex, QItemSelectionModel::Select);
	selectionModel->setCurrentIndex(modelIndex, 
			QItemSelectionModel::Select);
	setPushButton();
}

void PlotDataWidget::removeDialog(const QModelIndex &/*parent*/,
		int start, int end)
{
	for (int i = start; i <= end; i++) {
		delete dialogList.takeAt(i);
	}
	setPushButton();
	setAction();
}

void PlotDataWidget::setAction()
{
	// チェックされている項目があるか調べる
	bool isChecked = false;
	for (int i = 0, j = plotListModel->rowCount(); i < j; i++) {
		if (plotListModel->data(plotListModel->index(i),
					Qt::CheckStateRole) == Qt::Checked) {
			isChecked = true;
			break;
		}
	}
	emit setPlotEnabled(isChecked);
}

bool PlotDataWidget::hasItem() const
{
	return plotListModel->rowCount() > 0;
}

QStringList PlotDataWidget::commandList() const
{
	QStringList commandList;
	for (int i = 0, j = plotListModel->rowCount(); i < j; i++) {
		QModelIndex modelIndex = plotListModel->index(i);
		if (plotListModel->data(modelIndex, 
					Qt::CheckStateRole) == Qt::Checked) {
			commandList << plotListModel->plot(modelIndex).command();
		}
	}
	return commandList;
}

void PlotDataWidget::closeDialog()
{
	while (!dialogList.isEmpty()) {
		delete dialogList.takeFirst();
	}
}
