#include <QScrollBar>
#include <QListWidget>
#include <QTimer>
#include "properties_editor.h"
#include "qvariantedit.h"
#include "core.h"


PropertiesEditor::PropertiesEditor(QWidget * parent): QWidget(parent), Ui::PropertiesEditor() {
	setupUi(this);
	flags_delegate = new FlagsDelegate();
	flags_delegate->hideEnumerator("Internal");
	int pfi = SHS::staticMetaObject.indexOfEnumerator("PropertyFlag");
	if (pfi >= 0) flags_delegate->setEnum(SHS::staticMetaObject.enumerator(pfi));
	type_delegate = new VariantTypeDelegate();
	treeProps->setItemDelegateForColumn(1, flags_delegate);
	treeProps->setItemDelegateForColumn(2, type_delegate);
	treeProps->header()->resizeSection(0, 150);
	treeProps->header()->resizeSection(1, 200);
	treeProps->header()->resizeSection(2, 150);
	treeProps->header()->resizeSection(3, 250);
	icon_plugin = QIcon(":/icons/plugin.png");
}


PropertiesEditor::~PropertiesEditor() {
	//delete type_delegate;
	//delete flags_delegate;
}


void PropertiesEditor::addProperties(const PropertyStorage & p) {
	foreach (const PropertyStorage::Property & i, p)
		addProperty(i);
	filterList();
	updateTreeLayout();
}


PropertyStorage PropertiesEditor::properties() {
	PropertyStorage ret;
	for (int i = 0; i < treeProps->topLevelItemCount(); ++i) {
		QTreeWidgetItem * ti = treeProps->topLevelItem(i);
		PropertyStorage::Property p;
		p.name = ti->text(0);
		p.flags = ti->data(1, Qt::DisplayRole).toInt();
		p.comment = ti->text(4);
		p.value = qobject_cast<QVariantEdit * >(treeProps->itemWidget(ti, 3))->value();
		ret << p;
	}
	return ret;
}


void PropertiesEditor::reloadPlugins() {
}


bool PropertiesEditor::eventFilter(QObject * o, QEvent * e) {
	return QWidget::eventFilter(o, e);
}


void PropertiesEditor::on_buttonPropAdd_clicked() {
	PropertyStorage::Property p(uniqueName("property"), "", QString());
	treeProps->setCurrentItem(addProperty(p));
	emit propertiesChanged();
}


void PropertiesEditor::on_buttonPropDup_clicked() {
	QTreeWidgetItem * ci = treeProps->currentItem();
	if (ci == 0) return;
	treeProps->blockSignals(true);
	QTreeWidgetItem * ti = ci->clone();
	ti->setText(0, uniqueName(ti->text(0)));
	ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
	treeProps->addTopLevelItem(ti);
	QVariantEdit * ve = new QVariantEdit();
	connect(ve, SIGNAL(valueChanged(QVariant)), this, SIGNAL(propertiesChanged()));
	bool pbs = blockSignals(true);
	setVariantValue(ve, ci->data(2, Qt::DisplayRole).toInt());
	blockSignals(pbs);
	treeProps->setItemWidget(ti, 3, ve);
	treeProps->setCurrentItem(ti);
	treeProps->blockSignals(false);
	emit propertiesChanged();
}


void PropertiesEditor::addDefaultProperties() {
	QStringList epl;
	for (int i = 0; i < treeProps->topLevelItemCount(); ++i)
		epl << treeProps->topLevelItem(i)->text(0);
	foreach (const PropertyStorage::Property & p, defaults)
		if (!epl.contains(p.name))
			addProperty(p);
	emit propertiesChanged();
}


void PropertiesEditor::on_buttonPropDelete_clicked() {
	treeProps->blockSignals(true);
	qDeleteAll(treeProps->selectedItems());
	treeProps->blockSignals(false);
	emit propertiesChanged();
}


void PropertiesEditor::on_buttonPropClear_clicked() {
	treeProps->blockSignals(true);
	treeProps->clear();
	treeProps->blockSignals(false);
	emit propertiesChanged();
}


void PropertiesEditor::on_buttonPropUp_clicked() {
	QList<QTreeWidgetItem * > sil = treeProps->selectedItems();
	treeProps->clearSelection();
	treeProps->blockSignals(true);
	for (int i = 0; i < sil.size(); ++i) {
		QTreeWidgetItem * ti = sil[i];
		int ind = treeProps->indexOfTopLevelItem(ti);
		if (ind > 0) {
			if (sil.contains(treeProps->topLevelItem(ind - 1))) continue;
			QVariant def = ((QVariantEdit*)(treeProps->itemWidget(ti, 3)))->value();
			treeProps->takeTopLevelItem(ind);
			treeProps->insertTopLevelItem(ind - 1, ti);
			QVariantEdit * ve = new QVariantEdit();
			connect(ve, SIGNAL(valueChanged(QVariant)), this, SIGNAL(propertiesChanged()));
			ve->setValue(def);
			ve->setDisabled(ti->isDisabled());
			treeProps->setItemWidget(ti, 3, ve);
		}
	}
	treeProps->blockSignals(false);
	foreach (QTreeWidgetItem * i, sil) i->setSelected(true);
	updateTreeLayout();
	emit propertiesChanged();
}


void PropertiesEditor::on_buttonPropDown_clicked() {
	QList<QTreeWidgetItem * > sil = treeProps->selectedItems();
	treeProps->clearSelection();
	treeProps->blockSignals(true);
	int count = treeProps->topLevelItemCount();
	for (int i = sil.size() - 1; i >= 0; --i) {
		QTreeWidgetItem * ti = sil[i];
		int ind = treeProps->indexOfTopLevelItem(ti);
		if (ind < count - 1) {
			if (sil.contains(treeProps->topLevelItem(ind + 1))) continue;
			QVariant def = ((QVariantEdit*)(treeProps->itemWidget(ti, 3)))->value();
			treeProps->takeTopLevelItem(ind);
			treeProps->insertTopLevelItem(ind + 1, ti);
			QVariantEdit * ve = new QVariantEdit();
			connect(ve, SIGNAL(valueChanged(QVariant)), this, SIGNAL(propertiesChanged()));
			ve->setValue(def);
			ve->setDisabled(ti->isDisabled());
			treeProps->setItemWidget(ti, 3, ve);
		}
	}
	treeProps->blockSignals(false);
	foreach (QTreeWidgetItem * i, sil) i->setSelected(true);
	updateTreeLayout();
	emit propertiesChanged();
}


void PropertiesEditor::on_treeProps_itemChanged(QTreeWidgetItem * item, int column) {
	if (column == 2) {
		int type = item->data(2, Qt::DisplayRole).toInt();
		treeProps->blockSignals(true);
		item->setData(2, Qt::DisplayRole, type);
		treeProps->blockSignals(false);
		if (qobject_cast<QVariantEdit * >(treeProps->itemWidget(item, 3)))
			QMetaObject::invokeMethod(this, "setVariantValue", Qt::QueuedConnection, Q_ARG(void*, treeProps->itemWidget(item, 3)), Q_ARG(int, type));
	} else
		emit propertiesChanged();
}


void PropertiesEditor::filterList() {
	QString f = lineFilter->text();
	QLocale loc;
	for (int i = 0; i < treeProps->topLevelItemCount(); ++i) {
		QTreeWidgetItem * ti = treeProps->topLevelItem(i);
		bool match = false;
		match = match || (ti->text(0).contains(f, Qt::CaseInsensitive) || ti->text(4).contains(f, Qt::CaseInsensitive));
		QVariantEdit * ve = qobject_cast<QVariantEdit * >(treeProps->itemWidget(ti, 3));
		if (ve)
			match = match || (ve->value().toString().contains(f, Qt::CaseInsensitive));
		match = match || flags_delegate->displayText(ti->data(1, Qt::DisplayRole), loc).contains(f, Qt::CaseInsensitive);
		match = match || type_delegate->displayText(ti->data(2, Qt::DisplayRole), loc).contains(f, Qt::CaseInsensitive);
		ti->setHidden(!match);
	}
}


void PropertiesEditor::setVariantValue(void * ve_, int type) {
	QVariantEdit * ve = (QVariantEdit * )ve_;
	QVariant v;
	if (type == qMetaTypeId<QAD::Enum>()) v = QVariant::fromValue(QAD::Enum());
	if (type == qMetaTypeId<QAD::File>()) v = QVariant::fromValue(QAD::File());
	if (type == qMetaTypeId<QAD::Dir>()) v = QVariant::fromValue(QAD::Dir());
	if (v.isValid()) ve->setValue(v);
	else ve->setValue(QVariant((QVariant::Type)type));
	//qDebug() << "type =" << type << ", val=" << v;
	updateTreeLayout();
	emit propertiesChanged();
}


QString PropertiesEditor::uniqueName(QString n) {
	QStringList el;
	for (int i = 0; i < treeProps->topLevelItemCount(); ++i)
		el << treeProps->topLevelItem(i)->text(0);
	return ::uniqueName(n, el);
}


QTreeWidgetItem * PropertiesEditor::addProperty(const PropertyStorage::Property & p) {
	treeProps->blockSignals(true);
	QTreeWidgetItem * ti = new QTreeWidgetItem(QStringList() << p.name << QString::number(p.flags));
	ti->setData(2, Qt::DisplayRole, p.value.userType());
	ti->setText(3, "");
	ti->setText(4, p.comment);
	ti->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
	if (p.flags & SHS::Plugin)
		ti->setIcon(1, icon_plugin);
	treeProps->addTopLevelItem(ti);
	QVariantEdit * ve = new QVariantEdit();
	connect(ve, SIGNAL(valueChanged(QVariant)), this, SIGNAL(propertiesChanged()));
	ve->setValue(p.value);
	treeProps->setItemWidget(ti, 3, ve);
	if ((p.flags & SHS::Internal) == SHS::Internal) {
		ti->setDisabled(true);
		ve->setDisabled(true);
	}
	treeProps->blockSignals(false);
	return ti;
}
