/*
 * Cueplot: a GUI front-end to gnuplot
 * Copyright (C) 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 "PlotListModel.h"

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QMimeData>
#include <QtCore/QUrl>
#include <QtGui/QTextDocument>

Q_DECLARE_METATYPE(Plot)

PlotListModel::PlotListModel(QObject *parent)
: QAbstractListModel(parent)
{
}

QVariant PlotListModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid() || index.row() >= plotList.size()) {
		return QVariant();
	}
	if (role == Qt::DisplayRole || role == Qt::EditRole) {
		Plot plot = plotList.at(index.row());
		return plot.isFunction() ? plot.function() : plot.dataFile();
	} else if (role == Qt::WhatsThisRole) {
		return "plot " + Qt::escape(plotList.at(index.row()).command());
	} else if (role == Qt::CheckStateRole) {
		return checkList.at(index.row());
	} else if (role == Qt::UserRole) {
		return qVariantFromValue(plotList.at(index.row()));
	} else if (role == Qt::UserRole + 1) {
		return plotList.at(index.row()).isFunction();
	}
	return QVariant();

}

bool PlotListModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
	int row, int column, const QModelIndex &parent)
{
	if (action == Qt::IgnoreAction) {
		return true;
	}
	if (!data->hasUrls() || column > 0) {
		return false;
	}
	int beginRow = parent.isValid() ? parent.row() : row;
	// 負の値になるときは項目を最後に追加する
	if (beginRow < 0) {
		beginRow = rowCount();
	}
	QList<QUrl> list = data->urls();
	QStringList fileList;
	int rows = 0;
	for (int i = 0, j = list.size(); i < j; i++) {
		if (!list.at(i).isValid()) {
			continue;
		}
		QString file = list.at(i).toLocalFile();
		// ファイルのみを追加する
		if (!QFileInfo(file).isFile()) {
			continue;
		}
		fileList << 
#if QT_VERSION >= 0x040200
			QDir::toNativeSeparators(file);
#else
			QDir::convertSeparators(file);
#endif
		rows++;
	}
	insertRows(beginRow, rows);
	for (int i = 0; i < rows; i++) {
		int idx = beginRow + i;
		Plot plot;
		plot.setFunction(false);
		plot.setDataFile(fileList.at(i));
		setPlot(index(idx), plot);
	}
	return true;
}

QVariant PlotListModel::headerData(int section, Qt::Orientation orientation,
		int role) const
{
	if (role != Qt::DisplayRole) {
		return QVariant();
	}
	return ((orientation == Qt::Horizontal) 
			? tr("Column %1") : tr("Row %1")).arg(section);
}

Qt::ItemFlags PlotListModel::flags(const QModelIndex &index) const
{
	if (!index.isValid() || index.row() >= plotList.size() 
			|| index.model() != this) {
		return Qt::ItemIsDropEnabled;
	}
	return QAbstractItemModel::flags(index) // | Qt::ItemIsDragEnabled
		| Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
}

bool PlotListModel::insertRows(int row, int count, const QModelIndex &parent)
{
	if (count < 1 || row < 0 || row > rowCount() || parent.isValid()) {
		return false;
	}
	beginInsertRows(QModelIndex(), row, row + count - 1);

	for (int i = 0; i < count; i++) {
		plotList.insert(row, Plot());
		checkList.insert(row, Qt::Checked);
	}

	endInsertRows();
	return true;
}

QStringList PlotListModel::mimeTypes() const
{
	QStringList types;
	types << "text/uri-list";
	return types;
}

bool PlotListModel::removeRows(int row, int count, const QModelIndex &parent)
{
	if (count < 1 || row < 0 || (row + count) > rowCount() 
			|| parent.isValid()) {
		return false;
	}
	beginRemoveRows(QModelIndex(), row, row + count - 1);

	for (int i = 0; i < count; i++) {
		plotList.removeAt(row);
		checkList.removeAt(row);
	}

	endRemoveRows();
	return true;
}

int PlotListModel::rowCount(const QModelIndex &parent) const
{
	return parent.isValid() ? 0 : plotList.size();
}

bool PlotListModel::setData(const QModelIndex &index, const QVariant &value, 
		int role)
{
	if (!index.isValid() || index.row() >= plotList.size()) {
		return false;
	}
	if (role == Qt::EditRole) {
		QString str = value.toString();
		if (str.isEmpty()) {
			return false;
		}
		int row = index.row();
		Plot plot = plotList.at(row);
		plot.isFunction() ? plot.setFunction(str) : plot.setDataFile(str);
		plotList[row] = plot;
		emit dataChanged(index, index);
		return true;
	} else if (role == Qt::CheckStateRole) {
		int state = value.toInt();
		if (state != Qt::Unchecked && state != Qt::PartiallyChecked
				&& state != Qt::Checked) {
			return false;
		}
		checkList[index.row()] = static_cast<Qt::CheckState>(state);
		emit dataChanged(index, index);
		return true;
	} else if (role == Qt::UserRole) {
		plotList[index.row()] = qVariantValue<Plot>(value);
		emit dataChanged(index, index);
		return true;
	}
	return false;
}

Qt::DropActions PlotListModel::supportedDropActions() const
{
	return Qt::CopyAction | Qt::MoveAction;
}

bool PlotListModel::swapRow(int row1, int row2, const QModelIndex &parent)
{
	if (row1 < 0 || row1 > rowCount() || row2 < 0 || row2 > rowCount() 
			|| parent.isValid()) {
		return false;
	}
	plotList.swap(row1, row2);
	checkList.swap(row1, row2);
	return true;
}

Plot PlotListModel::plot(const QModelIndex &index) const
{
	return qVariantValue<Plot>(data(index, Qt::UserRole));
}

bool PlotListModel::setPlot(const QModelIndex &index, const Plot &plot) 
{
	return setData(index, qVariantFromValue(plot), Qt::UserRole);
}
