#include "database_buses.h"
#include <QScrollBar>
#include <QFileDialog>
#include <QImageReader>
#include <QMessageBox>
#include <QBuffer>
#include "database_storage.h"
#include "ccm_SHS_shared.h"


DatabaseBuses::DatabaseBuses(QWidget * parent): QWidget(parent), Ui::DatabaseBuses() {
	setupUi(this);
	ask_for_save = true;
	spinEndpoints->setSpecialValueText("Unlimited");
	spinEndpoints->setValue(1);
	auto dcnl = PIIODevice::availableClasses();
	for (const auto & c: dcnl) {
		QListWidgetItem * ni = new QListWidgetItem();
		ni->setCheckState(Qt::Unchecked);
		ni->setText(PI2QString(c));
		listClasses->addItem(ni);
	}
	cur_id = prev_id = -1;
	menu.addAction(actionAddBus);
	menu.addAction(actionRemoveBus);
	tree->setModel(&model);
	connect(SHCORE, SIGNAL(changedPlugins()), this, SLOT(reloadPlugins()));
	connect(tree, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(popupMenuBus(QPoint)));
	connect(tree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(treeSelectionChanged()));
	connect(tree->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(treeClicked(QModelIndex)));
}


DatabaseBuses::~DatabaseBuses() {
}


void DatabaseBuses::reload() {
	int bus_pv = tree->verticalScrollBar()->value(), bus_row = tree->currentIndex().row();
	tree->selectionModel()->blockSignals(true);
	model.setQuery("SELECT id,name FROM bus_types");
	tree->selectionModel()->blockSignals(false);
	filterList();
	tree->verticalScrollBar()->setValue(bus_pv);
	widgetBus->setEnabled(false);
	cur_id = -1;
	if (bus_row >= 0) {
		tree->setCurrentIndex(model.index(bus_row, 0));
		//treeClicked(tree->currentIndex());
	}
}


void DatabaseBuses::reloadPlugins() {
	QString pv = comboPlugin->currentText();
	comboPlugin->clear();
	comboPlugin->addItem("");
	auto pl = RUNTIME->plugins_manager->localInterface().loadedPlugins();
	for (const auto & p: pl) {
		if (!p.plugin) continue;
		if (p.type != SHPluginBase::Bus) continue;
		comboPlugin->addItem(p.plugin->name());
		if (pv == p.plugin->name())
			comboPlugin->setCurrentIndex(comboPlugin->count() - 1);
	}
	properties->reloadPlugins();
}


void DatabaseBuses::showID(int id) {
	ask_for_save = false;
	for (int i = 0; i < model.rowCount(); ++i) {
		if (model.record(i).value("id").toInt() == id) {
			tree->setCurrentIndex(model.index(i, 0));
			break;
		}
	}
	ask_for_save = true;
}


void DatabaseBuses::loadImageIntoLabel(ImageView * l) {
	QList<QByteArray> sif(QImageReader::supportedImageFormats());
	QString f;
	foreach (const QByteArray & i, sif) {
		if (!f.isEmpty()) f += " ";
		f += "*.";
		f += i;
	}
	QString ret = QFileDialog::getOpenFileName(this, "Select image", "./", QString("Images(%1)").arg(f));
	if (ret.isEmpty()) return;
	QImage im(ret);
	if (im.isNull()) return;
	l->setImage(im);
}


QSqlQuery DatabaseBuses::updateQuery(int id) {
	if (id < 0) return QSqlQuery();
	BusType bus;
	for (int i = 0; i < listClasses->count(); ++i)
		if (listClasses->item(i)->checkState() == Qt::Checked)
			bus.io_classes << listClasses->item(i)->text();
	bus.id = id;
	bus.name = lineName->text();
	bus.description = lineDescription->text();
	bus.plugin = comboPlugin->currentText();
	bus.properties = properties->properties();
	bus.color = colorButton->color();
	bus.width = spinWidth->value();
	bus.endpoints = spinEndpoints->value();
	bus.image_bus_scale = evalScaleB->value();
	bus.image_endpoint_scale = evalScaleE->value();
	bus.image_bus = labelImageB->pixmap().toImage();
	bus.image_end = labelImageE->pixmap().toImage();
	QSqlQuery q;
	q.prepare(QString("UPDATE bus_types SET name=:n,data=:d WHERE id=%1").arg(id));
	q.bindValue(":n", bus.name);
	q.bindValue(":d", piqSerialize(bus));
	return q;
}


void DatabaseBuses::popupMenuBus(QPoint p) {
	if (!tree->selectionModel()->hasSelection()) {
		tree->setCurrentIndex(tree->indexAt(p));
	}
	treeClicked(tree->currentIndex());
	actionRemoveBus->setEnabled(tree->selectionModel()->hasSelection());
	menu.popup(tree->viewport()->mapToGlobal(p));
}


void DatabaseBuses::filterList() {
	QString f = lineFilter->text();
	for (int i = 0; i < model.rowCount(); ++i)
		tree->setRowHidden(i, QModelIndex(), !(model.index(i, 0).data().toString().contains(f, Qt::CaseInsensitive) ||
											   model.index(i, 1).data().toString().contains(f, Qt::CaseInsensitive)));
}


void DatabaseBuses::treeSelectionChanged() {
	if (tree->selectionModel()->selectedRows().isEmpty()) {
		widgetBus->setEnabled(false);
	} else {
		widgetBus->setEnabled(true);
	}
}


void DatabaseBuses::on_actionAddBus_triggered() {
	QSqlQuery q("INSERT INTO bus_types (name) VALUES ('new bus')");
	int id = q.lastInsertId().toInt();
	BusType bus;
	bus.id = id;
	bus.name = "new bus";
	bus.properties = properties->defaultProperties();
	q.prepare(QString("UPDATE bus_types SET data=:d WHERE id=%1").arg(id));
	q.bindValue(":d", piqSerialize(bus));
	q.exec();
	reload();
	tree->selectionModel()->select(model.index(model.rowCount() - 1, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current);
	tree->setCurrentIndex(model.index(model.rowCount() - 1, 0));
	//treeClicked(model.index(model.rowCount() - 1, 0));
	//properties->addDefaultProperties();
}


void DatabaseBuses::on_actionRemoveBus_triggered() {
	QModelIndexList sl = tree->selectionModel()->selectedRows();
	QString qs("DELETE FROM bus_types WHERE id IN (");
	for (int i = 0; i < sl.size(); ++i) {
		if (i > 0) qs += ",";
		qs += QString::number(sl[i].data().toInt());
	}
	qs += ")";
	QSqlQuery q(qs);
	prev_id = cur_id = -1;
	reload();
	prev_id = cur_id = -1;
}


void DatabaseBuses::on_buttonReset_clicked() {
	treeClicked(tree->currentIndex());
}


void DatabaseBuses::on_buttonCommit_clicked() {
	if (cur_id < 0) return;
	QSqlQuery q(updateQuery(cur_id));
	if (!q.exec())
		qDebug() << q.lastError();
	reload();
}


void DatabaseBuses::treeClicked(const QModelIndex & index) {
	properties->setDefaultProperties(SHCORE->default_bus_properties);
	cur_id = model.record(index.row()).value("id").toInt();
	if (cur_id != prev_id && prev_id > 0 && ask_for_save) {
		QSqlQuery cur_query = updateQuery(prev_id);
		if ((prev_query.lastQuery() != cur_query.lastQuery() ||
			prev_query.boundValues() != cur_query.boundValues()) &&
			!prev_query.lastQuery().isEmpty()) {
			int mb = QMessageBox::question(this, "SH Designer Database", tr("Save changes?"), QMessageBox::Yes | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Yes);
			if (mb == QMessageBox::Cancel) {
				tree->selectionModel()->blockSignals(true);
				for (int i = 0; i < model.rowCount(); ++i)
					if (model.record(i).value("id").toInt() == prev_id) {
						tree->setCurrentIndex(model.index(i, 0));
						break;
					}
				tree->selectionModel()->blockSignals(false);
				return;
			}
			if (mb == QMessageBox::Yes)
				cur_query.exec();
		}
	}
	prev_id = cur_id;
	QSqlQuery q(QString("SELECT * FROM bus_types WHERE id=%1").arg(cur_id));
	QSqlRecord r;
	if (q.next())
		r = q.record();
	else {
		widgetBus->setEnabled(false);
		return;
	}
	widgetBus->setEnabled(true);
	lineName->setText(r.value("name").toString());
	BusType bus = piqDeserialize<BusType>(r.value("data").toByteArray());
	bus.id = cur_id;
	bus.name = lineName->text();
	lineDescription->setText(bus.description);
	spinEndpoints->setValue(bus.endpoints);
	spinWidth->setValue(bus.width);
	colorButton->setColor(bus.color);
	labelImageB->setImage(bus.image_bus);
	labelImageE->setImage(bus.image_end);
	evalScaleB->setValue(bus.image_bus_scale);
	evalScaleE->setValue(bus.image_endpoint_scale);
	for (int i = 0; i < listClasses->count(); ++i)
		listClasses->item(i)->setCheckState(bus.io_classes.contains(listClasses->item(i)->text()) ? Qt::Checked : Qt::Unchecked);
	bool dbpfound = false;
	for (int i = 0; i < comboPlugin->count(); ++i) {
		if (comboPlugin->itemText(i) == bus.plugin) {
			comboPlugin->setCurrentIndex(i);
			dbpfound = true;
			break;
		}
	}
	if (!dbpfound) {
		comboPlugin->addItem(QIcon(":/icons/dialog-warning.png"), bus.plugin);
		comboPlugin->setCurrentIndex(comboPlugin->count() - 1);
	}
	properties->setProperties(SHDatabaseStorage::loadBusProperties(&busitem, bus.properties, comboPlugin->currentText()));
	prev_query = updateQuery(cur_id);
}
