#include "device_watcher.h"
#include <QApplication>
#include <QMessageBox>
#include <QFileDialog>
#include <QProcess>
#include <piserial.h>
#include <piqt.h>
#include "plugins_window.h"
#include "SH_plugins_manager.h"


DeviceWatcher::DeviceWatcher() {
	qRegisterMetaType<QAction*>();
	last = 0;
	sep = new QAction(); sep->setSeparator(true);
	menu.addAction(sep);
	menu.addAction(QIcon(":/icons/plugin.png"), "Plugins ...", this, SLOT(pluginsTriggered()));
	QAction * sa = new QAction(); sa->setSeparator(true);
	menu.addAction(sa);
	menu.addAction(QIcon(":/icons/application-exit.png"), "Exit", qApp, SLOT(quit()));
	tray.setContextMenu(&menu);
	tray.setToolTip("SHS Device watcher");
	tray.setIcon(QIcon(":/icons/Device_Watcher.png"));
	tray.show();
	RUNTIME->plugins_manager->localInterface().loadPlugins();
	collectDeviceTypes();
	connect(&tray, SIGNAL(messageClicked()), this, SLOT(messageTriggered()));
	PIThread::start(2000);
}


DeviceWatcher::~DeviceWatcher() {
	tray.hide();
}


void DeviceWatcher::run() {
	PISet<PIString> cur_ser;
	PIStringList ssl = PISerial::availableDevices();
	piForeachC (PIString & s, ssl) {
		cur_ser << s;
	}
	//piCout << prev_ser << cur_ser << ssl;
	for (int i = 0; i < actions.size(); ++i) {
		QAction * a = actions[i];
		PIString dev = Q2PIString(a->property("_device").toString());
		if (!ssl.contains(dev)) {
			piCout << "remove action" << dev;
			QMetaObject::invokeMethod(this, "removeAction", Qt::QueuedConnection, Q_ARG(QAction*, a));
			actions.removeAt(i);
			--i;
		}
	}
	if (prev_ser == cur_ser) return;
	PISet<PIString> tcs = cur_ser;
	cur_ser.subtract(prev_ser);
	prev_ser = tcs;
	PIVector<PIString> csv = cur_ser.toVector();
	piForeachC (PIString & s, csv) {
		checkDevice(s);
	}
}


void DeviceWatcher::checkDevice(const PIString & path) {
	if (!hexplugin) return;
	piCout << "check" << path;
	PISerial ser;
	ser.setPath(path);
	ser.setSpeed(PISerial::S9600);
	if (!ser.open()) return;
	SHS::Object obj;
	for (int j = 0; j < devices.size_s(); ++j) {
		DeviceType & d(devices[j]);
		ser.write(d.request);
		piCout << "send" << d.request.toHex();
		PIByteArray ans = ser.readForTime(100.);
		piCout << "recv" << ans.toHex();

		QVariantMap args;
		if (hexplugin->receivePacket(obj, obj, d.answer, PI2QByteArray(ans), args) != SHPluginBasePacket::rrSuccess)
			continue;
		///if (!parseCommand(PI2QByteArray(ans), d.answer, args)) continue;
		QAction * a = new QAction();
		a->setIcon(d.icon);
		a->setText(QString("%1: %2").arg(PI2QString(path), d.designer_name));
		a->setProperty("_device", PI2QString(path));
		a->setProperty("_address", args["id"].toInt());
		a->setProperty("_designer_path", d.designer_path);
		a->setProperty("_designer_name", d.designer_name);
		QMetaObject::invokeMethod(this, "addAction", Qt::QueuedConnection, Q_ARG(QAction*, a));
	}
	ser.close();
}


void DeviceWatcher::collectDeviceTypes() {
	devices.clear();
	hexplugin = (SHPluginBasePacket *)(RUNTIME->plugins_manager->localInterface().getPlugin("HexLang", SHPluginBase::Packet).plugin);
	qDebug() << hexplugin;
	if (!hexplugin) return;
	auto pl = RUNTIME->plugins_manager->localInterface().getPlugins(SHPluginBase::Extra);
	SHS::Object obj;
	for (const auto & p: pl) {
		SHPluginBaseExtra * plugin = (SHPluginBaseExtra * )p.plugin;
		DeviceType dt;
		dt.str_request = plugin->deviceWatcherRequest();
		dt.str_answer = plugin->deviceWatcherAnswer();

		SHS::Command cmd;
		cmd.arguments["__text__"] = dt.str_request;
		hexplugin->prepareCommand(obj, obj, cmd);
		dt.request = Q2PIByteArray(hexplugin->sendPacket(obj, obj, cmd));

		dt.answer.arguments["__text__"] = dt.str_answer;
		hexplugin->prepareCommand(obj, obj, dt.answer);

		dt.designer_name = plugin->deviceWatcherDesignerName();
		dt.designer_path = plugin->deviceWatcherDesignerPath();
		dt.icon = plugin->deviceWatcherDesignerIcon();
		devices << dt;
	}
}


void DeviceWatcher::addAction(QAction * a) {
	connect(a, SIGNAL(triggered(bool)), this, SLOT(actionTriggered()));
	menu.insertAction(sep, a);
	QString dev = a->property("_device").toString();
	QString dname = a->property("_designer_name").toString();
	tray.showMessage(QString("New device (%1)").arg(dev), QString("Open %1").arg(dname));
	last = a;
	actions << a;
}


void DeviceWatcher::removeAction(QAction * a) {
	delete a;
	if (last == a) last = 0;
}


void DeviceWatcher::actionTriggered() {
	QAction * a = qobject_cast<QAction*>(sender());
	if (!a) return;
	if (a == last) last = 0;
	QString dev = a->property("_device").toString();
	QString dpath = a->property("_designer_path").toString();
	QString address = a->property("_address").toString();
	QProcess::startDetached(findExecutable(dpath), QStringList() << "-d" << dev << "-a" << address);
	//delete a;
}


void DeviceWatcher::messageTriggered() {
	if (!last) return;
	last->trigger();
	last = 0;
}


void DeviceWatcher::pluginsTriggered() {
	PluginsWindow w;
	w.exec();
}
