#include "historyview.h"

#include <QEvent>
#include <QScrollBar>


HistoryView::HistoryView(QWidget * parent): QListWidget(parent) {
	setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
	setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
	setSelectionMode(QAbstractItemView::MultiSelection);
	setEditTriggers(NoEditTriggers);
	active_     = true;
	duplicates_ = false;
	index       = 0;
	setLimit(32);
	setHistoryColor(palette().color(QPalette::Highlight));
	connect(this, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(itemClicked(QListWidgetItem *)));
	connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
	registerAction(-1, tr("History cleared"), QImage(":/icons/edit-delete-history.png"));
}


HistoryView::~HistoryView() {}


QByteArray HistoryView::current() const {
	QListWidgetItem * ci = currentItem();
	if (!ci) return QByteArray();
	int i = row(ci);
	if (i < 0 || i >= history_.size()) return QByteArray();
	return history_[i].command;
}


void HistoryView::addEntry(int action, int count_, const QString & suffix) {
	if (!active_) return;
	QByteArray ba;
	emit commandRequest(ba);
	if (!duplicates_)
		if (current() == ba) return;
	int cnt = count();
	for (int i = index; i < cnt; ++i)
		if (i >= 0) delete takeItem(index);
	QListWidgetItem * li = new QListWidgetItem(actions_.value(action).icon, actionText(action, count_) + suffix);
	blockSignals(true);
	addItem(li);
	setCurrentItem(li);
	index = count();
	history_.resize(index);
	history_.back() = Entry(action, ba);
	checkLimit();
	scrollToItem(item(index - 1));
	for (int i = 0; i < index; ++i)
		item(i)->setSelected(true);
	blockSignals(false);
	emit changed();
	emit redoAvailable(false);
	emit undoAvailable((index > 1));
	emit clearAvailable(history_.count() > 1);
}


void HistoryView::registerAction(int action, const QString & text, const QImage & icon) {
	actions_[action] = HistoryView::Action(action, text, icon);
}


QString HistoryView::actionText(int action, int count_) {
	return QString(actions_.value(action).text).replace("%count", QString::number(count_));
}


void HistoryView::checkLimit() {
	if (count() < limit_ + 1) return;
	int c = count() - limit_;
	for (int i = 0; i < c; ++i) {
		if (i >= index - 1) {
			if (count() < 2) break;
			delete takeItem(1);
			history_.remove(1);
		} else {
			if (count() < 1) break;
			delete takeItem(0);
			history_.pop_front();
			index--;
		}
	}
	if (index < 1) index = 1;
	if (index > count()) index = count();
}


void HistoryView::changeEvent(QEvent * e) {
	QListWidget::changeEvent(e);
	switch (e->type()) {
	case QEvent::LanguageChange: actions_[-1].text = tr("History cleared"); break;
	default: break;
	}
}


void HistoryView::itemClicked(QListWidgetItem * item) {
	if (!active_) return;
	if (index == row(item) + 1) return;
	index = row(item) + 1;
	// qDebug() << actions[index - 1].command;
	emit commandExecute(history_[index - 1].command);
	emit changed();
	itemSelectionChanged();
}


void HistoryView::itemSelectionChanged() {
	if (!active_) return;
	if (index < 1) index = 1;
	// qDebug() << "changed" << count();
	int vpos = verticalScrollBar()->value();
	blockSignals(true);
	setCurrentItem(item(index - 1));
	for (int i = 0; i < index; ++i)
		item(i)->setSelected(true);
	for (int i = index; i < count(); ++i)
		item(i)->setSelected(false);
	blockSignals(false);
	verticalScrollBar()->setValue(vpos);
	emit redoAvailable(index < count());
	emit undoAvailable((index > 1));
}


void HistoryView::setLimit(int l) {
	limit_ = l;
	checkLimit();
	emit redoAvailable(index < count());
	emit undoAvailable((index > 1));
}


void HistoryView::setHistoryColor(const QColor & c) {
	color_ = c;
	QPalette pal(palette());
	pal.setColor(QPalette::Highlight, color_);
	pal.setColor(QPalette::HighlightedText, pal.color(QPalette::Text));
	setPalette(pal);
}


void HistoryView::clear(bool silent) {
	history_.clear();
	QListWidget::clear();
	if (!silent) addEntry(-1);
	emit clearAvailable(false);
	emit redoAvailable(index < count());
	emit undoAvailable((index > 1));
}


void HistoryView::undo() {
	if (index <= 1) return;
	index--;
	emit commandExecute(history_[index - 1].command);
	emit changed();
	itemSelectionChanged();
}


void HistoryView::redo() {
	if (index >= count()) return;
	index++;
	emit commandExecute(history_[index - 1].command);
	emit changed();
	itemSelectionChanged();
}
