#include "server.h"
#include "SH_packages.h"
#include "SH_network_types.h"
#include <piqt.h>
#include <QDebug>
#include <QScrollBar>
#include <QMdiSubWindow>
#include <QMetaEnum>
#include <QListWidget>
#include <QElapsedTimer>
#include <QCryptographicHash>
#include <QResource>
#include <piethernet.h>
#include <edockwidget.h>
#include <qad_locations.h>

//const double keepAliveInterval_s = 2.;

enum ColumnnClient {
	ccOS,
	ccArch,
	ccHostname,
	ccID,
	ccRole,
	ccChannel,
	ccIP,
	ccConnected,
	ccSendBytes,
	ccRecBytes,
	ccSendSpeed,
	ccRecSpeed,
};




Server::Server(bool reservation): EMainWindow(), Ui::Server(), core(reservation) {
	setupUi(this);
	PACKAGES;
	labelVersion->setText(QString("PIP %1   Qt %2   SHS %3   SHS_UI_SYNC %4")
						  .arg(PI2QString(PIPVersion()), QString(qVersion()), QString(SHS_VERSION_NAME))
						  .arg(SHS_UISYNC_VERSION));
	//treeBlocks->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
	textDebug->installEventFilter(this);
	labelCloudName->setText(PI2QString(getThisCloudName()));
	menu_log = new QMenu();
	menu_log->addAction(actionClearLog);
	menu_debug = new QMenu();
	menu_debug->addAction(actionClearDebug);
	icon_property = QIcon(":/icons/code-variable.png");
	log_category[SHServer::LogInfo   ] = "info" ;
	log_category[SHServer::LogSuccess] = "ok"   ;
	log_category[SHServer::LogWarning] = "warn" ;
	log_category[SHServer::LogError  ] = "error";
	logView->registerCategory(tr("Info"   ), log_category[SHServer::LogInfo   ], QImage(":/icons/dialog-information.png"));
	logView->registerCategory(tr("Success"), log_category[SHServer::LogSuccess], QImage(":/icons/dialog-ok-apply.png"   ), Qt::NoBrush, QColor(0xD0FFD0));
	logView->registerCategory(tr("Warning"), log_category[SHServer::LogWarning], QImage(":/icons/dialog-warning.png"    ), Qt::NoBrush, QColor(0xFFFFA0));
	logView->registerCategory(tr("Error"  ), log_category[SHServer::LogError  ], QImage(":/icons/dialog-error.png"      ), Qt::NoBrush, QColor(0xFFD0D0));
	packet_icons[0] = QIcon(":/icons/packet-.png");
	packet_icons[SHS::Input] = QIcon(":/icons/packet-i.png");
	packet_icons[SHS::Output] = QIcon(":/icons/packet-o.png");
	packet_icons[SHS::Plugin] = QIcon(":/icons/packet-p.png");
	packet_icons[SHS::Input | SHS::Output] = QIcon(":/icons/packet-io.png");
	packet_icons[SHS::Input | SHS::Plugin] = QIcon(":/icons/packet-ip.png");
	packet_icons[SHS::Output | SHS::Plugin] = QIcon(":/icons/packet-op.png");
	packet_icons[SHS::Input | SHS::Output | SHS::Plugin] = QIcon(":/icons/packet-iop.png");
	connect(&(core.engine), SIGNAL(variableHistoryAdded(QString,QPair<QDateTime,double>)), this, SLOT(variableHistoryAdded(QString,QPair<QDateTime,double>)), Qt::DirectConnection);
	connect(&(core.engine), SIGNAL(variableHistoryRemoved(QString,int)), this, SLOT(variableHistoryRemoved(QString,int)), Qt::DirectConnection);
	connect(&core, SIGNAL(loadedUI        ()), this, SLOT(loadedUI        ()));
	connect(&core, SIGNAL(loadedDAT       ()), this, SLOT(loadedDAT       ()));
	connect(&core, SIGNAL(loadedCM        ()), this, SLOT(loadedCM        ()));
	connect(&core, SIGNAL(loadedVAR       ()), this, SLOT(loadedVAR       ()));
	connect(&core, SIGNAL(startedAsMain   ()), this, SLOT(startedAsMain   ()));
	connect(&core, SIGNAL(startedAsReserve()), this, SLOT(startedAsReserve()));
	core.engine.setDebugWidget(logView);
	session.setFile(QAD::userPath(QAD::ltConfig, "session"));
	session.addEntry(this);
	session.load();
	timer_update = startTimer(1000);
	timer_log = startTimer(100);
}


Server::~Server() {
	delete menu_debug;
	delete menu_log;
}


void Server::closeEvent(QCloseEvent * e) {
	session.save();
	session.clear();
}


void Server::disableGraphics() {
	dockVariables->hide();
	core.engine.no_graphics = true;
	no_graphics = true;
}


void Server::loadedUI() {
	QMdiSubWindow * sw = mdiArea->addSubWindow(core.form);
	core.form->show();
	sw->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowMinMaxButtonsHint);
	sw->installEventFilter(this);
	sw->move(0, 0);
}


void Server::loadedDAT() {
	labelProject->setText(PI2QString(core.server_name_));
	labelKey->setText(PI2QString(core.server_key_));
}


void Server::loadedCM() {
}


void Server::loadedVAR() {
	if (no_graphics) return;
	treeVariables->clear();
	for (int i = 0; i < core.vars.size(); ++i) {
		const SHS::ScriptVariable & v(core.vars[i]);
		auto * ti = new QTreeWidgetItem();
		ti->setText(0, v.name);
		treeVariables->addTopLevelItem(ti);
	}
	showVariables();
}


void Server::startedAsMain() {
	labelRole->setText(tr("Main"));
	labelRole->setIcon(QIcon(":/icons/led_on.png"));
}


void Server::startedAsReserve() {
	labelRole->setText(tr("Reserve"));
	labelRole->setIcon(QIcon(":/icons/led_3.png"));
}


void Server::prepare() {
	objectTree->create(RUNTIME->server_data.blocks);
}


void Server::timerEvent(QTimerEvent * e) {
	if (e->timerId() == timer_update) {
		core.rmutex.lock();
		widgetDevices->set(core.state.devices);
		widgetClients->set(core.state.clients);
		core.rmutex.unlock();
	}
	if (e->timerId() == timer_log) {
		core.lmutex.lock();
		while (!core.log_queue.isEmpty()) {
			LogEntry l = core.log_queue.dequeue();
			QString msg = QString("%1 - %2").arg(l.time.toString(), l.text);
			logView->addText(msg, log_category[l.type]);
			qDebug() << "log:" << msg;
		}
		core.lmutex.unlock();
	}
}


void Server::showVariables() {
	if (no_graphics) return;
	for (int i = 0; i < treeVariables->topLevelItemCount(); ++i) {
		auto * ti = treeVariables->topLevelItem(i);
		PIPair<ullong, double> vv = core.engine.getVariableValue(ti->text(0));
		ti->setText(1, QString::number(vv.second));
		ti->setText(2, QDateTime::fromMSecsSinceEpoch(vv.first).toString("dd.MM.yyyy  hh:mm:ss"));
	}
}


bool Server::eventFilter(QObject * o, QEvent * e) {
	if (e->type() == QEvent::ContextMenu) {
		if (o == textDebug) {
			menu_debug->popup(((QContextMenuEvent*)e)->globalPos());
			return true;
		}
	}
	if (e->type() == QEvent::Close) {
		e->ignore();
		return true;
	}
	return EMainWindow::eventFilter(o, e);
}


void Server::variableHistoryAdded(QString vname, QPair<QDateTime, double> value) {
	showVariables();
}


void Server::variableHistoryRemoved(QString vname, int count) {
	showVariables();
}


void Server::on_buttonRestart_clicked() {
	emit core.zeroFailure();
	QMetaObject::invokeMethod(this, "restartRequest", Qt::QueuedConnection);
}


void Server::on_buttonCloudNameCopy_clicked() {
	QApplication::clipboard()->setText(labelCloudName->text());
}
