#include "server_starter.h"
#include "SH_base.h"
#include "SH_plugins_manager.h"
#include <qad_locations.h>



ServerStarter::ServerStarter(): QObject() {
	confpath = QAD::userPath(QAD::ltConfig, "server");
	failpath = QAD::userPath(QAD::ltCache, "failures");
	baf_path = QAD::userPath(QAD::ltCache, "data") + ".baf";
	QString ph;
	if (QFile::exists(confpath)) {
		QPIConfig conf(confpath, QIODevice::ReadOnly);
		QString baf = conf.getValue("baf_path", "").toString().trimmed();
		if (!baf.isEmpty())
			baf_path = baf;
		max_failures = conf.getValue("max_failures", max_failures).toInt();
		log_add_time = conf.getValue("log_add_time", log_add_time).toBool();
		log_add_dev = conf.getValue("log_add_dev", log_add_dev).toBool();
		log_io = conf.getValue("log_io", log_io).toBool();
		max_log_kb = conf.getValue("max_log_kb", max_log_kb).toDouble();
		reservation = conf.getValue("reservation", reservation).toBool();
		ph = conf.getValue("admin_passwd").toString();
	}
	if (ph.isEmpty())
		admin_password = passwordHash("");
	else
		admin_password = PIByteArray::fromHex(Q2PIString(ph));
	//piCout << "last admin_passwd" << admin_passwd.toHex();
}


ServerStarter::~ServerStarter() {
	destroy();
}


void ServerStarter::writePassword(const PIByteArray & ph) {
	//piCout << " set admin_passwd" << ph.toHex();
	QPIConfig conf(confpath, QIODevice::ReadWrite);
	conf.setValue("admin_passwd", PI2QString(ph.toHex()));
}


void ServerStarter::init() {
	destroy();
	checkConfig();
	server = new Server(reservation);
	server->core.admin_log_max_size = piRound(max_log_kb * 1024);
	server->core.admin_password = admin_password;
	connect(server, SIGNAL(restartRequest()), this, SLOT(restart()));
	if (no_graphics)
		server->disableGraphics();
	server->core.engine.connection()->setLogAddTime(log_add_time);
	server->core.engine.connection()->setLogAddDevice(log_add_dev);
	server->core.engine.connection()->setLogIO(log_io);
	connect(&(server->core), SIGNAL(zeroFailure()), this, SLOT(zeroFailure()));
	connect(&(server->core), SIGNAL(restart(QString)), this, SLOT(restart(QString)), Qt::QueuedConnection);
}


void ServerStarter::destroy() {
	RUNTIME->connection.stop();
	piDeleteSafety(server);
	RUNTIME->plugins_manager->localInterface().unloadPlugins();
}


void ServerStarter::start() {
	if (!server) return;
	server->prepare();
	RUNTIME->connection.start();
	server->core.startEth();
	if (!no_graphics)
		server->show();
	QTimer::singleShot(10000, &(server->core), SIGNAL(zeroFailure()));
}


bool ServerStarter::checkFailure() {
	QFile f(failpath);
	if (!f.open(QIODevice::ReadWrite)) {
		qDebug() << "[ServerStarter] Error: can`t open \"" << failpath << "\", exit";
		QApplication::quit();
		return true;
	}
	int fails = 0;
	QTextStream s(&f);
	if (f.size() >= 1)
		s >> fails;
	if (fails >= max_failures) {
		qDebug() << "[ServerStarter] Error: too many failures, standby ...";
		return true;
	}
	f.resize(0);
	s.seek(0);
	s << (fails + 1);
	qDebug() << "write fails" << fails;
	return false;
}


#define CHECK_CONF(e) if (!conf.isEntryExists(#e)) s << #e << " = " << e << "\n";

void ServerStarter::checkConfig() {
	QPIConfig conf(confpath, QIODevice::ReadOnly);
	conf.close();
	QFile f(confpath);
	if (!f.open(QIODevice::ReadWrite)) {
		qDebug() << "[ServerStarter] Warning: can`t open \"" << confpath << "\"";
		return;
	}
	f.seek(f.size());
	QTextStream s(&f);
	auto baf_path = src_baf_path;
	CHECK_CONF(baf_path    );
	CHECK_CONF(max_failures);
	CHECK_CONF(log_add_time);
	CHECK_CONF(log_add_dev );
	CHECK_CONF(log_io      );
	CHECK_CONF(reservation );
	CHECK_CONF(max_log_kb  );
}

#undef CHECK_CONF


void ServerStarter::zeroFailure() {
	QFile f(failpath);
	if (!f.open(QIODevice::ReadWrite)) {
		qDebug() << "[ServerStarter] Error: can`t open \"" << failpath << "\", exit";
		QApplication::quit();
		return;
	}
	f.resize(0);
	QTextStream s(&f);
	s << int(0);
}


void ServerStarter::restart(QString baf) {
	src_baf_path = baf;
	if (!baf.isNull()) baf_path = baf;
	init();
	if (checkFailure())
		server->core.baf_path = Q2PIString(baf_path);
	else
		server->core.loadBAF(Q2PIString(baf_path));
	start();
}
