#ifndef SERVER_CORE_H
#define SERVER_CORE_H

#include <QTimer>
#include <picli.h>
#include <picloudserver.h>
#include <piliterals_bytes.h>
#include "script_engine.h"
#include "server_client.h"
#include "SH_assembly.h"
#include "SH_ui_loader.h"
#include "SH_ui_sync.h"


class ServerCore: public QObject, public SHMulticast {
	Q_OBJECT
	PIOBJECT_SUBCLASS(ServerCore, SHMulticast)
	friend class Server;
	friend class ServerClient;
	friend class ServerStarter;
public:
	ServerCore(bool reservation = false);
	~ServerCore();
	
	void loadRCC(const QString & p);
	void loadUI (const QString & p);
	void loadQS (const QString & p);
	void loadDAT(const QString & p);
	void loadCM (const QString & p);
	void loadVAR(const QString & p);
	void loadBAF(const PIString & p);
	void loadProject(const QString & p);
	void startEth();
	void start();

	SHSScriptEngine engine;
	PIByteArray admin_password;
	uint admin_log_max_size = 65_KiB;

private:
	void timerEvent(QTimerEvent *) override;
	void receivedSH(PIByteArray data, uint rec_id) override;
	void addressesChanged() override;
	void sendToAll(const PIByteArray & data, SHServer::ClientRole role, bool no_check = false);
	void log(const QString & text, SHServer::LogEntryType type = SHServer::LogInfo);
	void message(const QString & text, int type = 0);
	void receivedIdentification(ServerClient * r, PIByteArray data);
	void receivedKey(ServerClient * r, PIByteArray data);
	bool hasServer(const PIString & ip) const;
	bool loadPlugins();
	void startAsMain();
	void startAsReserve();
	void selectNewMain();
	void buildBlockTree();
	void saveUIState();
	void restoreUIState();
	void uploadedBAF(const PIByteArray & baf, ServerClient * r);
	PacketParameterList adminParameters() const;
	EVENT_HANDLER1(void, newTCPConnection, PIEthernet * , client);
	EVENT_HANDLER1(void, newCloudConnection, PICloudServer::Client * , client);

	enum ServerState {ssStart, ssSync, ssWorkMain, ssWorkReserve};
	
	struct ServerSync {
		int seed;
		ServerState state;
		PIString ip;
		int missed;
	};

	struct MessageEntry {
		QDateTime time;
		QString text;
		int type;
	};

	typedef PIPair<PIString, PIString> PISSPair;
	
	QWidget * form = nullptr;
	SHUISync sync;
	SHAssembly ass;
	PIEthernet eth_tcp;
	PICloudServer cloud_server;
	PIMutex rmutex, lmutex, smutex;
	QQueue<LogEntry> log_queue;
	PIDeque<LogEntry> admin_log, admin_log_history;
	QQueue<PacketMessage> message_queue;
	PIVector<PIEthernet*> eth_mcast;
	PIByteArray ui_content, bqr_content;
	PacketServerState state;
	PIMap<PIIODevice * , ServerClient * > remotes;
	QDir script_dir;
	QString lqs_err_msg, script, file_ui_state, file_ui_state_new, file_script;
	QList<SHS::ScriptVariable> vars;
	PIVector<ServerSync> servers;
	PIVector<PISSPair> addresses_server;
	PIString my_ip = "127.0.0.1", main_ip, baf_path, df_device, server_name_, server_key_;
	ServerState server_state = ServerCore::ssStart;
	ServerClient * df_client = nullptr;
	SHSUiLoader ui_loader;
	uint ui_hash = 0, rcc_hash = 0;
	uint admin_log_cur_size = 0;
	int timer = 0, timer_sync = 0, timer_admin = 0, timer_save_state = 0, lqs_err_line = -1, sync_skip = 0, main_missed = 0;
	int seed = 0 , seed_main = 0;
	bool with_reservation = false;

private slots:
	void connDataReceivedEvent(QString from, QByteArray data);
	void variableHistoryAdded(QString vname, QPair<QDateTime, double> value);
	void scriptError(int line, QString file, QString message, QString stack);
	void scriptLog(QString text, int type) {log(text, (SHServer::LogEntryType)type);}
	void scriptDebug(QString text);
	void scriptMessage(QString text, int type) {message(text, type);}
	void IOLog(QString text);

signals:
	void restart(QString baf_path);
	void loadedUI ();
	void loadedDAT();
	void loadedCM ();
	void loadedVAR();
	void startedAsMain();
	void startedAsReserve();
	void zeroFailure();

};

#endif // SERVER_CORE_H
