/*
 * mucaffiliationsmodel.cpp
 * Copyright (C) 2006  Remko Troncon
 *
 * 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#include <QMimeData>
#include <QFont>
#include <QVariant>

#include "mucaffiliationsmodel.h"

using namespace XMPP;


MUCAffiliationsModel::MUCAffiliationsModel() : QStandardItemModel(Unknown,2)
{
	QFont font;
	font.setBold(true);
	QVariant font_variant = qVariantFromValue(font);
	for (int i = 0; i < Unknown; i++) {
		QModelIndex ind = index(i, 0, QModelIndex());
		setData(ind,QVariant(affiliationlistindexToString((AffiliationListIndex) i)));
		setData(ind,font_variant,Qt::FontRole);
		insertColumns(0,1,ind);
		insertColumns(1,1,ind);
		enabled_[(AffiliationListIndex) i] = false;
	}
	setHorizontalHeaderLabels(QStringList() << tr("JID") << tr("Reason"));
}

Qt::ItemFlags MUCAffiliationsModel::flags(const QModelIndex &index) const
{
	Qt::ItemFlags a;
	if (!index.parent().isValid()) {
		// List headers
		if (enabled_[(AffiliationListIndex) index.row()]) {
			a |= Qt::ItemIsDropEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
		}
	}
	else {
		a |= Qt::ItemIsDropEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
	}
	return a;
}

Qt::DropActions MUCAffiliationsModel::supportedDropActions() const
{
	return Qt::MoveAction;
}

bool MUCAffiliationsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int, const QModelIndex &parent)
{
	if ( (parent.isValid() && parent.column() != 0)
		|| !data || action != Qt::MoveAction
		|| !( data->hasFormat("application/vnd.text.list") || data->hasFormat("text/plain") ) )
	{
		return false;
	}

	// Decode the data
	QStringList newItems;
	int nb_rows = 0;
	if (data->hasFormat("application/vnd.text.list")) {
		QByteArray encodedData = data->data("application/vnd.text.list");
		QDataStream stream(&encodedData, QIODevice::ReadOnly);
		while (!stream.atEnd()) {
			QString text;
			stream >> text;
			newItems << text;
			nb_rows++;
		}
	}
	else if (data->hasFormat("text/plain")) {
		QString item(data->data("text/plain"));
		if (Jid(item).isValid()) {
			newItems += item;
			nb_rows++;
		}
	}

	if (nb_rows == 0)
		return false;

	// Determine the correct index
	QModelIndex real_index;
	if (parent.isValid())  {
		real_index = (parent.parent().isValid() ? parent.parent() : parent);
	}
	else {
		if (row > 0)
			real_index = index(row-1,0,parent);
		else if (row == 0)
			real_index = index(0,0,parent);
		else
			real_index = index(Outcast,0,parent);
	}
	int real_row = rowCount(real_index);

	// Insert the data
	insertRows(real_row, nb_rows, real_index);
	foreach (QString text, newItems) {
		QModelIndex idx = index(real_row, 0, real_index);
		setData(idx, text);
		real_row++;
	}

	return true;
}

QStringList MUCAffiliationsModel::mimeTypes() const
{
	QStringList types;
	types << "application/vnd.text.list";
	types << "text/plain";
	return types;
}

QMimeData* MUCAffiliationsModel::mimeData(const QModelIndexList &indexes) const
{
 	QMimeData *mimeData = new QMimeData();
	QByteArray encodedData;
	QDataStream stream(&encodedData, QIODevice::WriteOnly);
	foreach (QModelIndex index, indexes) {
		if (index.isValid() && index.column() == 0) {
			QString text = data(index, Qt::DisplayRole).toString();
			stream << text;
		}
	}
	mimeData->setData("application/vnd.text.list", encodedData);
	return mimeData;
}

void MUCAffiliationsModel::resetAffiliationLists()
{
	items_.clear();
	resetAffiliationList(MUCItem::Outcast);
	resetAffiliationList(MUCItem::Member);
	resetAffiliationList(MUCItem::Admin);
	resetAffiliationList(MUCItem::Owner);
}

void MUCAffiliationsModel::resetAffiliationList(MUCItem::Affiliation a)
{
	emit layoutAboutToBeChanged();
	enabled_[(AffiliationListIndex) affiliationToIndex(a)] = false;
	QModelIndex index = affiliationListIndex(a);
	if (hasChildren(index)) {
		removeRows(0,rowCount(index),index);
	}
	emit layoutChanged();
}

void MUCAffiliationsModel::setAffiliationListEnabled(MUCItem::Affiliation a, bool b)
{
	emit layoutAboutToBeChanged();
	QModelIndex index = affiliationListIndex(a);
	enabled_[(AffiliationListIndex) index.row()] = b;
	emit layoutChanged();
}

QString MUCAffiliationsModel::affiliationlistindexToString(AffiliationListIndex list)
{
	if (list == Members)
		return tr("Members");
	else if (list == Admins)
		return tr("Administrators");
	else if (list == Owners)
		return tr("Owners");
	else if (list == Outcast)
		return tr("Banned");
	return QString();
}

QModelIndex MUCAffiliationsModel::affiliationListIndex(MUCItem::Affiliation a)
{
	AffiliationListIndex i = affiliationToIndex(a);
	if (i == Unknown) {
		qWarning("mucconfigdlg.cpp: Unexpected affiliation");
		return QModelIndex();
	}
	return index(i, 0, QModelIndex());
}

MUCAffiliationsModel::AffiliationListIndex MUCAffiliationsModel::affiliationToIndex(MUCItem::Affiliation a)
{
	if (a == MUCItem::Member)
		return Members;
	else if (a == MUCItem::Admin)
		return Admins;
	else if (a == MUCItem::Owner)
		return Owners;
	else if (a == MUCItem::Outcast)
		return Outcast;
	else
		return Unknown;
}


void MUCAffiliationsModel::addItems(const QList<MUCItem>& items)
{
	bool dirty = false;
	foreach(MUCItem item, items) {
		QModelIndex list = affiliationListIndex(item.affiliation());
		if (list.isValid() && !item.jid().isEmpty()) {
			if (!dirty) {
				emit layoutAboutToBeChanged();
			}
			int row = rowCount(list);
			if (row == 0) {
				enabled_[(AffiliationListIndex) list.row()] = true;
			}
			insertRows(row,1,list);
			setData(index(row,0,list),QVariant(item.jid().full()));
			setData(index(row,1,list),QVariant(item.reason()));
			MUCItem i(MUCItem::UnknownRole,item.affiliation());
			i.setJid(item.jid());
			items_ += i;
			dirty = true;
		}
		else {
			qDebug("Unexpected item");
		}
	}
	if (dirty)
		emit layoutChanged();
}

QList<MUCItem> MUCAffiliationsModel::changes() const
{
	QList<MUCItem> items_old = items_;
	QList<MUCItem> items_delta;

	// Add all new items
	for (int i = 0; i < rowCount(QModelIndex()); i++) {
		QModelIndex list = index(i,0,QModelIndex());
		for(int j = 0; j < rowCount(list); j++) {
			Jid jid(data(index(j,0,list)).toString());
			MUCItem item(MUCItem::UnknownRole,indexToAffiliation(i));
			item.setJid(jid);
			if (!items_.contains(item)) {
				items_delta += item;
			}
			else
				items_old.removeAll(item);
		}
	}

	// Remove all old items not present in the delta
	foreach(MUCItem item_old, items_old) {
		bool found = false;
		foreach(MUCItem item_new, items_delta) {
			if (item_new.jid().compare(item_old.jid(),false)) {
				found = true;
				break;
			}
		}
		if (!found) {
			MUCItem item(MUCItem::UnknownRole,MUCItem::NoAffiliation);
			item.setJid(item_old.jid());
			items_delta += item;
		}
	}

	return items_delta;
}

MUCItem::Affiliation MUCAffiliationsModel::indexToAffiliation(int li)
{
	if (li == Members)
		return MUCItem::Member;
	else if (li == Admins)
		return MUCItem::Admin;
	else if (li == Owners)
		return MUCItem::Owner;
	else if (li == Outcast)
		return MUCItem::Outcast;
	else
		return MUCItem::UnknownAffiliation;
}

