#ifndef SH_NETWORK_TYPES_H
#define SH_NETWORK_TYPES_H

#include <QObject>
#include <QDateTime>
#include <QVariant>
#include <pistringlist.h>
#include <pitime.h>
#include "SH_types.h"


class PIIODevice;
struct PacketHeader;


class SHNetworkTypes: public QObject {
	Q_OBJECT
	Q_ENUMS(MulticastType)
	Q_ENUMS(ChannelType)
public:

	const static int clientPort    = 13361;
	const static int interfacePort = 13461;
	const static int cloudPort     = 13561;

	enum MulticastType {
		Request = 1,
		Reply,
		ServerNew = 0x10,
		ServerRemove,
		ServerPing,
		ServerAlreadyMain
	};

	enum ChannelType {
		None,
		TCP,
		Cloud,
	};

	enum PacketType {
		KeepAlive,
		Identification,
		KeyProbe,
		KeyProbeResult,
		ConnectingDone,
		ClientReady,
		GuiRestoreRCC,
		GuiRestoreUI,
		GuiSyncRCC,
		GuiSyncUI,
		GuiSyncDiff,
		GuiSyncEvent,
		GuiSyncVersionMismatch,
		Message,
		IdentificationRequest,
		ServerInfoRequest,
		ServerInfo,
		NetworkVersionMismatch,
		ChangeUserRole,
		ChangeUserRoleResult,

		AdminBAFUpload = 100,
		AdminBAFOk,
		AdminBAFFail,
		AdminDeviceForwardingRequest,
		AdminDeviceForwardingPermit,
		AdminDeviceForwardingSelect,
		AdminDeviceForwardingWrite,
		AdminDeviceForwardingRead,
		AdminPasswordFail,
		AdminPasswordAccepted,
		AdminRestart,
		AdminLog,
		AdminState,
		AdminParameterList,
		AdminSetParameter,
		AdminScriptError,
		AdminRestartQueued,

		RemotePultPackageNameRequest = 200,
		RemotePultPackageName,
		RemotePultPackageContentRequest,
		RemotePultPackageContent,

		GraphicRequest = 300,
		GraphicData,
		GraphicDone,
	};

	static PIByteArray makeHeader(int t);
	static PacketHeader takeHeader(PIByteArray & ba);

};


#define ID(n) PIMETA(id=n)


struct ServerDevice {
	ServerDevice(const PIIODevice * d = 0, const PIStringList & nl = PIStringList());
	ID(10) PIStringList names;
	ID(11) PIString fullpath;
};

struct LogEntry {
	ID(1) QDateTime time;
	ID(2) QString text;
	ID(3) int type;
};

struct ServerAddress {
	PIString ipAddress() const;
	PIString fullAddress() const;
	uint hash() const;
	ID(1) SHNetworkTypes::ChannelType channel = SHNetworkTypes::None;
	ID(2) QString server;
	ID(3) QString cloud_name;
	ID(4) ushort port = 0;
};

struct ServerClientInfo {
	ID(1) uint id = 0;
	ID(2) int channel = SHNetworkTypes::None;
	ID(3) int role = 0;
	ID(4) int OS_type = SHPlatform::Unknown;
	ID(5) QString OS_version;
	ID(6) QString OS_arch;
	ID(7) QString hostname;
	ID(8) QString address;
	ID(9) QDateTime connected_time;
	ID(10) ullong sended_bytes = 0U;
	ID(11) ullong received_bytes = 0U;
	ID(12) QString send_speed;
	ID(13) QString receive_speed;
	ID(14) int user_role = 0;
};

struct ServerDeviceInfo {
	ID(1) QString classname;
	ID(2) QString path;
	ID(3) int mode;
	ID(4) ullong sended_bytes = 0U;
	ID(5) ullong received_bytes = 0U;
	ID(6) QString send_speed;
	ID(7) QString receive_speed;
};

struct ServerVariable {
	ID(1) QString name;
	ID(2) QString store;
	ID(3) ullong changed = 0U;
	ID(4) double value = 0.;
};

struct ServerUserRole {
	QString displayName() const;
	ID(1) QString name;
	ID(2) QString display_name;
	ID(4) QByteArray password_hash;
	ID(5) int privilege = 0;
	ID(6) int index = 0;
};


struct PacketHeader {
	PacketHeader(int t = -1);
	int type;
};

struct PacketHashes {
	uint hash_ui;
	uint hash_rcc;
};

struct PacketIdentification {
	PacketIdentification();
	static PacketIdentification makeLocal(int r = 0, int net_version = 0, int sync_version = 0);
	ID(10) int net_version;
	ID(11) int sync_version;
	ID(12) int os_type;
	ID(13) int role; // SH_Server::ClientRole
	ID(20) uint machine_id;
	ID(14) PIString os_version;
	ID(15) PIString arch;
	ID(16) PIString hostname;
	ID(17) PIString shs_version;
	ID(18) PIByteArray admin_password;
	ID(19) PacketHashes hashes;
};

struct PacketServerInfo {
	bool isValid() const;
	void setUserRoles(const QVector<SHS::UserRole> roles);
	PIByteArray toByteArray() const;
	PIString displayVersion() const;
	bool compatible() const;
	static PacketServerInfo fromByteArray(PIByteArray ba);
	ID(10) PacketIdentification identify;
	ID(11) PIString connect_address;
	ID(12) PIString name;
	ID(14) int channel = SHNetworkTypes::None; // SHNetworkTypes::ChannelType
	ID(15) ServerAddress address;
	ID(16) PIVector<ServerUserRole> user_roles;
};

struct PacketMessage {
	PacketMessage(int ty = -1, const PIString & te = PIString(), const PIDateTime & tm = PIDateTime());
	bool isValid() const;
	ID(10) int type;
	ID(11) PIString text;
	ID(12) PIDateTime time;
};

struct PacketServerLog {
	ID(10) PIDeque<LogEntry> entries;
};

struct PacketServerState {
	ID(10) PIVector<ServerClientInfo> clients;
	ID(11) PIVector<ServerVariable> variables;
	ID(12) PIVector<ServerDeviceInfo> devices;
};

struct PacketParameter {
	PacketParameter(int i = 0, QString n = QString(), QVariant v = QVariant()) {id = i; name = n; value = v;}
	ID(10) int id;
	ID(11) QString name;
	ID(12) QVariant value;
};

struct PacketParameterList {
	ID(10) PIVector<PacketParameter> parameters;
};

struct PacketScriptError {
	ID(10) QString message;
	ID(11) QString stack;
	ID(12) QString file;
	ID(13) int line = 0;
	ID(14) QString project;
};


#undef ID


Q_DECLARE_METATYPE(PacketServerInfo)


#endif // SH_NETWORK_TYPES_H
