/*
 * Copyright (c) 2010 Kevin Smith
 * Licensed under the GNU General Public License v3.
 * See Documentation/Licenses/GPLv3.txt for more information.
 */

#include "Swift/QtUI/Roster/QtTreeWidgetItem.h"
#include "Swift/QtUI/Roster/QtTreeWidget.h"

#include <qdebug.h>
#include <QtAlgorithms>
#include <algorithm>

namespace Swift {

QtTreeWidgetItem::QtTreeWidgetItem(QtTreeWidgetItem* parentItem) : QObject(), textColor_(0,0,0), backgroundColor_(255,255,255) {
	parent_ = parentItem;
	shown_ = true;
	expanded_ = true;
}


void QtTreeWidgetItem::setText(const String& text) {
	displayName_ = P2QSTRING(text);
	displayNameLower_ = displayName_.toLower();
	emit changed(this);
}

void QtTreeWidgetItem::setStatusText(const String& text) {
	statusText_ = P2QSTRING(text);
	emit changed(this);
}

void QtTreeWidgetItem::setAvatarPath(const String& path) {
	avatar_ = QIcon(P2QSTRING(path));
	emit changed(this);
}

void QtTreeWidgetItem::setStatusShow(StatusShow::Type show) {
	statusShowType_ = show;
	int color = 0;
	switch (show) {
		case StatusShow::Online: color = 0x000000; mergedShowType_ = StatusShow::Online; break;
		case StatusShow::Away: color = 0x336699; mergedShowType_ = StatusShow::Away; break;
	 	case StatusShow::XA: color = 0x336699; mergedShowType_ = StatusShow::Away; break;
		case StatusShow::FFC: color = 0x000000; mergedShowType_ = StatusShow::Online; break;
		case StatusShow::DND: color = 0x990000; mergedShowType_ = show; break;
		case StatusShow::None: color = 0x7F7F7F; mergedShowType_ = show; break;
	}
	setTextColor(color);
	emit changed(this);
}

void QtTreeWidgetItem::setTextColor(unsigned long color) {
	textColor_ = QColor(
	 					((color & 0xFF0000)>>16),
	 					((color & 0xFF00)>>8), 
	 					(color & 0xFF));
}

void QtTreeWidgetItem::setBackgroundColor(unsigned long color) {
	backgroundColor_ = QColor(
	 					((color & 0xFF0000)>>16),
	 					((color & 0xFF00)>>8), 
	 					(color & 0xFF));
}

void QtTreeWidgetItem::setExpanded(bool expanded) {
	expanded_ = expanded;
	emit changed(this);
}

void QtTreeWidgetItem::hide() {
	shown_ = false;
	emit changed(this);
}

void QtTreeWidgetItem::show() {
	shown_ = true;
	emit changed(this);
}

bool QtTreeWidgetItem::isShown() {
	return isContact() ? shown_ : shownChildren_.size() > 0;
}

QWidget* QtTreeWidgetItem::getCollapsedRosterWidget() {
	QWidget* widget = new QWidget();
	return widget;
}

QWidget* QtTreeWidgetItem::getExpandedRosterWidget() {
	QWidget* widget = new QWidget();
	return widget;
}

QtTreeWidgetItem::~QtTreeWidgetItem() {
	//It's possible (due to the way the roster deletes items in unknown order when it is deleted)
	// That the children will be deleted before the groups, or that the groups are deleted 
	// before the children. If the children are deleted first, they will let the parent know that
	// They've been deleted. If the parent is deleted first, it must tell the children not to
	// tell it when they're deleted. Everything will be deleted in the end, because all the
	// widgets are owned by the Roster in Swiften.
	if (parent_) {
		parent_->removeChild(this);
	}

	for (int i = 0; i < children_.size(); i++) {
		children_[i]->parentItemHasBeenDeleted();
	}
}

void QtTreeWidgetItem::parentItemHasBeenDeleted() {
	parent_ = NULL;
}

QtTreeWidgetItem* QtTreeWidgetItem::getParentItem() {
	return parent_;
}

void QtTreeWidgetItem::addChild(QtTreeWidgetItem* child) {
	children_.append(child);
	connect(child, SIGNAL(changed(QtTreeWidgetItem*)), this, SLOT(handleChanged(QtTreeWidgetItem*)));
	handleChanged(child);
}

void QtTreeWidgetItem::removeChild(QtTreeWidgetItem* child) {
	children_.removeAll(child);
	handleChanged(this);
}

void bubbleSort(QList<QtTreeWidgetItem*>& list) {
	bool done = false;
	for (int i = 0; i < list.size() - 1 && !done; i++) {
		done = true;
		for (int j = i + 1; j < list.size(); j++) {
			if (*(list[j]) < *(list[j - 1])) {
				done = false;
				QtTreeWidgetItem* lower = list[j];
				list[j] = list[j - 1];
				list[j - 1] = lower;
			}
		}
	}
}

void QtTreeWidgetItem::handleChanged(QtTreeWidgetItem* child) {
	/*We don't use the much faster qStableSort because it causes changed(child) and all sorts of nasty recursion*/
	//qStableSort(children_.begin(), children_.end(), itemLessThan);
	//bubbleSort(children_);
	std::stable_sort(children_.begin(), children_.end(), itemLessThan);
	shownChildren_.clear();
	for (int i = 0; i < children_.size(); i++) {
		if (children_[i]->isShown()) {
			shownChildren_.append(children_[i]);
		}
	}
	emit changed(child);
}

int QtTreeWidgetItem::rowCount() {
	//qDebug() << "Returning size of " << children_.size() << " for item " << displayName_;
	return shownChildren_.size();
}

int QtTreeWidgetItem::rowOf(QtTreeWidgetItem* item) {
	return shownChildren_.indexOf(item);
}

int QtTreeWidgetItem::row() {
	return parent_ ? parent_->rowOf(this) : 0;
}

QtTreeWidgetItem* QtTreeWidgetItem::getItem(int row) {
	//qDebug() << "Returning row " << row << " from item " << displayName_;
	Q_ASSERT(row >= 0);
	Q_ASSERT(row < rowCount());
	return shownChildren_[row];
}


QVariant QtTreeWidgetItem::data(int role) {
	if (!isContact()) {
		setTextColor(0xFFFFFF);
		setBackgroundColor(0x969696);
	}
 	switch (role) {
	 	case Qt::DisplayRole: return displayName_;
		case Qt::TextColorRole: return textColor_;
		case Qt::BackgroundColorRole: return backgroundColor_;
		case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant();
	 	case StatusTextRole: return statusText_;
		case AvatarRole: return avatar_;
		case PresenceIconRole: return getPresenceIcon();
	 	default: return QVariant();
	}
}

QString QtTreeWidgetItem::toolTipString() {
	return displayName_ + "\n " + statusText_;
}

QIcon QtTreeWidgetItem::getPresenceIcon() {
	QString iconString;
	switch (statusShowType_) {
	 	case StatusShow::Online: iconString = "online";break;
	 	case StatusShow::Away: iconString = "away";break;
	 	case StatusShow::XA: iconString = "away";break;
	 	case StatusShow::FFC: iconString = "online";break;
	 	case StatusShow::DND: iconString = "dnd";break;
	 	case StatusShow::None: iconString = "offline";break;
	}
	return QIcon(":/icons/" + iconString + ".png");
}

bool QtTreeWidgetItem::isContact() const {
	return children_.size() == 0;
}

bool QtTreeWidgetItem::isExpanded() {
	return expanded_;
}

bool QtTreeWidgetItem::operator<(const QtTreeWidgetItem& item) const {
	if (isContact()) {
		if (!item.isContact()) {
			return false;
		}
		return getStatusShowMerged() == item.getStatusShowMerged() ? getLowerName() < item.getLowerName() : getStatusShowMerged() < item.getStatusShowMerged();
	} else {
		if (item.isContact()) {
			return true;
		}
		return getLowerName() < item.getLowerName();
	}
}

bool itemLessThan(QtTreeWidgetItem* left, QtTreeWidgetItem* right) {
	return *left < *right;
}

}