/*
 * Copyright (c) 2010 Isode Limited.
 * All rights reserved.
 * See the COPYING file for more information.
 */

#include "Swift/QtUI/MUCSearch/QtMUCSearchWindow.h"

#include <qdebug.h>
#include <QMovie>
#include <QScrollBar>
#include <QTimer>
#include <QPushButton>

#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
#include "Swift/QtUI/MUCSearch/MUCSearchModel.h"
#include "Swift/QtUI/MUCSearch/MUCSearchDelegate.h"
#include "Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h"
#include "Swift/QtUI/QtSwiftUtil.h"

namespace Swift {

QtMUCSearchWindow::QtMUCSearchWindow() {
	ui_.setupUi(this);
#ifndef Q_OS_MAC
	setWindowIcon(QIcon(":/logo-icon-16.png"));
#endif
	setModal(true);
	ui_.filter_->hide();
	model_ = new MUCSearchModel();
	delegate_ = new MUCSearchDelegate();
	ui_.results_->setModel(model_);
	ui_.results_->setItemDelegate(delegate_);
	ui_.results_->setHeaderHidden(true);
	ui_.results_->setRootIsDecorated(true);
	ui_.results_->setAnimated(true);
	ui_.results_->setAlternatingRowColors(true);
	connect(ui_.searchButton, SIGNAL(clicked()), this, SLOT(handleSearch()));
	connect(ui_.service_, SIGNAL(activated(const QString&)), this, SLOT(handleSearch(const QString&)));
	connect(ui_.results_->selectionModel(), SIGNAL(selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT(handleSelectionChanged (const QItemSelection&, const QItemSelection&)));
	connect(ui_.results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&)));
	connect(ui_.results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&)));
	// Not using a button box, because i can't seem to be able to make the ok button non-default (on mac)
	connect(ui_.okButton, SIGNAL(clicked()), this, SLOT(accept()));
	ui_.okButton->setEnabled(false);
	connect(ui_.cancelButton, SIGNAL(clicked()), this, SLOT(reject()));

	throbber_ = new QLabel(tr("Searching"), ui_.results_);
	throbber_->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), throbber_));
	throbber_->setToolTip(tr("Searching"));

	hasHadScrollBars_ = false;
	updateThrobberPosition();
	setSearchInProgress(false);
}

QtMUCSearchWindow::~QtMUCSearchWindow() {

}

void QtMUCSearchWindow::resizeEvent(QResizeEvent* /*event*/) {
	updateThrobberPosition();
}

void QtMUCSearchWindow::updateThrobberPosition() {
	bool isShown = throbber_->isVisible();
	int resultWidth = ui_.results_->width();
	int resultHeight = ui_.results_->height();
	//throbberWidth = throbber_->movie()->scaledSize().width();
	//throbberHeight = throbber_->movie()->scaledSize().height();
	int throbberWidth = 16; /* This is nasty, but the above doesn't work! */
	int throbberHeight = 16;
	/* It's difficult (or I spent a while trying) to work out whether the scrollbars are currently shown and their appropriate size,
	 * because if you listen for the expanded/collapsed signals, you seem to get them before the scrollbars are updated.
	 * This seems an acceptable workaround.
	 */
	hasHadScrollBars_ |= ui_.results_->verticalScrollBar()->isVisible();
	int hMargin = hasHadScrollBars_ ? ui_.results_->verticalScrollBar()->width() + 2 : 2;
	int vMargin = 2; /* We don't get horizontal scrollbars */
	throbber_->setGeometry(QRect(resultWidth - throbberWidth - hMargin, resultHeight - throbberHeight - vMargin, throbberWidth, throbberHeight)); /* include margins */
	throbber_->setVisible(isShown);
}

void QtMUCSearchWindow::addSavedServices(const std::list<JID>& services) {
	ui_.service_->clear();
	foreach (const JID& jid, services) {
		ui_.service_->addItem(P2QSTRING(jid.toString()));
	}
	if (!services.empty()) {
		ui_.service_->setEditText(P2QSTRING(services.begin()->toString()));
	}
	else {
		ui_.service_->clearEditText();
	}
}

void QtMUCSearchWindow::handleActivated(const QModelIndex& index) {
	if (!index.isValid()) {
		return;
	}
	if (dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(index.internalPointer()))) {
		accept();
	}
}

void QtMUCSearchWindow::handleSearch() {
	handleSearch(ui_.service_->currentText());
}

void QtMUCSearchWindow::handleSearch(const QString& service) {
	if (!service.isEmpty()) {
		onSearchService(JID(Q2PSTRING(service)));
	}
}

void QtMUCSearchWindow::show() {
	QWidget::show();
	QWidget::activateWindow();
}

void QtMUCSearchWindow::clearList() {
	model_->clear();
}

void QtMUCSearchWindow::addService(const MUCService& service) {
	updateThrobberPosition();
	MUCSearchServiceItem* serviceItem = new MUCSearchServiceItem(P2QSTRING(service.getJID().toString()));
	if (service.getRooms().size() > 0) {
		foreach (MUCService::MUCRoom room, service.getRooms()) {
			new MUCSearchRoomItem(P2QSTRING(room.getNode()), serviceItem);
		}
	}
	else {
		new MUCSearchEmptyItem(serviceItem);
	}
	model_->addService(serviceItem);
	ui_.results_->expandAll();

}

void QtMUCSearchWindow::setSearchInProgress(bool searching) {
	if (searching) {
		throbber_->movie()->start();
	} else {
		throbber_->movie()->stop();
	}
	throbber_->setVisible(searching);
}

void QtMUCSearchWindow::accept() {
	MUCSearchRoomItem* room = getSelectedRoom();
	if (room) {
		onFinished(JID(Q2PSTRING(room->getNode()), Q2PSTRING(room->getParent()->getHost())));
	}
	else {
		onFinished(boost::optional<JID>());
	}
	QDialog::accept();
}

void QtMUCSearchWindow::reject() {
	onFinished(boost::optional<JID>());
	QDialog::reject();
}

void QtMUCSearchWindow::handleSelectionChanged(const QItemSelection&, const QItemSelection&) {
	ui_.okButton->setEnabled(getSelectedRoom());
}

MUCSearchRoomItem* QtMUCSearchWindow::getSelectedRoom() const {
	// Not using selectedIndexes(), because this seems to cause a crash in Qt (4.7.0) in the
	// QModelIndexList destructor.
	// This is a workaround posted in http://www.qtcentre.org/threads/16933 (although this case
	// was resolved by linking against the debug libs, ours isn't, and we're not alone)
	QItemSelection ranges = ui_.results_->selectionModel()->selection();
	QModelIndexList lstIndex;
	for (int i = 0; i < ranges.count(); ++i) {
		QModelIndex parent = ranges.at(i).parent();
		int right = ranges.at(i).model()->columnCount(parent) - 1;
		if (ranges.at(i).left() == 0 && ranges.at(i).right() == right) {
			for (int r = ranges.at(i).top(); r <= ranges.at(i).bottom(); ++r) {
				lstIndex.append(ranges.at(i).model()->index(r, 0, parent));
			}
		}
	}
	if (lstIndex.isEmpty()) {
		return NULL;
	}
	else {
		return dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(lstIndex.first().internalPointer()));
	}
}

}