/*---------------------------------------------------------------------------*/
/* remote_services.h                                                         */
/* copyright (c) innovaphone 2022                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#define TXT_MESSAGE_HDR_SIZE 5
#define RAW_MESSAGE_HDR_SIZE 5

#define TXT_MESSAGE      0
#define RAW_MESSAGE      1
#define PING_MESSAGE     2
#define PING_MESSAGE_ACK 3

enum MediaInterfaces {
    InfAudioIo,
    InfVideoIo,
    InfAudioIoChannel,
    InfVideoIoChannel,
};

enum MediaInterfaceMessages {
    EncodeResult,
};

enum TerminalServerPlatforms {
    WINDOWS_PLATFORM,
    CITRIX_PLATFORM,
    HORIZON_PLATFORM,
    UNKNOWN_PLATFORM,
};

class RemoteServiceDll : public istd::listElement<RemoteServiceDll> {
public:
	RemoteServiceDll(const char* server, const char* pipe) {
		this->server = _strdup(server);
		this->pipe = _strdup(pipe);
	}
	~RemoteServiceDll() {
		if (this->server) free(this->server);
		if (this->pipe) free(this->pipe);
	}
	char* server;
	char* pipe;
};

class RemoteMediaTone : public istd::listElement<RemoteMediaTone> {
public:
	RemoteMediaTone(const char* ident, const char* title, bool isRingtone = false) {
		this->ident = _strdup(ident);
		this->title = _strdup(title);
		this->isRingtone = isRingtone;
	}
	~RemoteMediaTone() {
		if (this->ident) free(this->ident);
		if (this->title) free(this->title);
	}
	char* ident;
	char* title;
	bool isRingtone;
};

class RemoteMediaDevice : public istd::listElement<RemoteMediaDevice> {
public:
	RemoteMediaDevice(const char* device, int type, int capabilities, const char* name) {
		this->name = _strdup(name);
		this->device = _strdup(device);
		this->type = type;
		this->capabilities = capabilities;
	}
	~RemoteMediaDevice() {
		if (this->name) free(this->name);
		if (this->device) free(this->device);
	}
	char* name;
	char* device;
	int type;
	int capabilities;
};

class ISignalingRemote {
public:
	virtual ~ISignalingRemote() {};

	virtual void CreateCall(void* context) = 0;
	virtual void DeleteCall(void* context) = 0;
};

class URemoteServices {
public:
	~URemoteServices() {};

	virtual void ClientConnected() = 0;
	virtual void ClientDisconnected() = 0;
	virtual void ServerConnected() = 0;
	virtual void ServerDisconnected() = 0;
	virtual void Message(const char* type, class json_io& msg, word base) = 0;
};

class IRemoteServices {
public:
	virtual ~IRemoteServices() {};

	virtual void SetRemoteServicesUser(class URemoteServices * user) = 0;
	virtual void SetRemoteServer(class IRemoteServer * remoteServer) = 0;
	virtual class IAudioIo * GetAudioIo() = 0;
	virtual class IRingerIo * GetRingerIo() = 0;
	virtual class IVideoIo * GetVideoIo() = 0;
	virtual class IMediaProvider * GetMediaProvider() = 0;
	virtual class ISignalingRemote * GetSignalingRemote() = 0;
	virtual bool IsServer() = 0;
	virtual void StartService() = 0;
};

class IRemoteServicesConnection {
public:
	virtual ~IRemoteServicesConnection() {};

	virtual void Message(const char* type, class json_io& msg, word base) = 0;
	virtual void RemoteClientConnected(class URemoteServicesConnection* user) = 0;
	virtual void RemoteClientDisconnected() = 0;
	virtual void RemoteServerConnected(class URemoteServicesConnection* user) = 0;
	virtual void RemoteServerDisconnected() = 0;
	virtual void RemoteClientMtu(int mtu) {};
};

class IRemoteServicesMedia {
public:
	virtual ~IRemoteServicesMedia() {};

	virtual int GetCallId() = 0;
	virtual int GetId() = 0;

	// Server Side
	// RemoteServicesIMedia -> RemoteServices (URemoteServicesMedia) -> RemoteServicesIAudioIo (IRemoteServicesMedia) -> RemoteServicesIAudioIoChannel
	virtual void SetMediaId(void* user, int id) = 0;

	// Client Side
	//RemoteServicesUAudioIo -> RemoteServices (URemoteServicesMedia) -> RemoteServicesUMedia (IRemoteServicesMedia)
	virtual void SetMediaIoChannel(void* mediaIoChannel) = 0;
	virtual void CloseMediaIoChannel(void* mediaIoChannel) = 0;
	virtual void MediaIoChannelInitialized(void* mediaIoChannel) = 0;
};

class URemoteServicesConnection {
public:
	virtual ~URemoteServicesConnection() {};

	virtual void Send(const void* buf, size_t len) = 0;
};

class URemoteServicesMedia {
public:
	virtual ~URemoteServicesMedia() {};

	// Server Side
	// RemoteServicesIAudioIo -> RemoteServices <- RemoteServicesIMedia
	virtual int GetCallId(void * user, MediaType mediaType) = 0;
	virtual int GetMediaId(void * user, MediaType mediaType) = 0;
	// RemoteServicesIMedia -> RemoteServices -> RemoteServicesIAudioIo (IRemoteServicesMedia) -> RemoteServicesIAudioIoChannel
	virtual void SetMediaId(void * user, MediaType mediaType, int id) = 0;
	virtual void MediaCloseComplete(class IRemoteServicesMedia * media) = 0;

	// Client Side
	// RemoteServicesUAudioIo -> RemoteServices -> RemoteServicesUMedia
	virtual UMediaIoChannel * GetUMediaIoChannel(MediaType mediaType, int callId) = 0;
	//RemoteServicesUAudioIo -> RemoteServices -> RemoteServicesUMedia (IRemoteServicesMedia)
	virtual void SetMediaIoChannel(void * mediaIoChannel, MediaType mediaType, int callId) = 0;
	virtual void CloseMediaIoChannel(void * mediaIoChannel, MediaType mediaType, int callId) = 0;
	virtual void MediaIoChannelInitialized(void * mediaIoChannel, MediaType mediaType, int callId) = 0;
	virtual void UMediaCloseComplete(class RemoteServicesUMedia* media) = 0;
};

class IRemoteServer {
public:
	virtual ~IRemoteServer() {};

	virtual void Send(const void* buf, size_t len) = 0;
	virtual void Close(bool deleteThis = false) = 0;
	virtual bool Start() = 0;
	virtual void SetURemoteServer(class URemoteServer* user) = 0;
	virtual void RemoteSessionConnected(bool connected) = 0;
	virtual void UserOptions(class json_io& msg, word base, bool pbx) = 0;
	virtual enum TerminalServerPlatforms GetPlatform() = 0;
	virtual void ClientDllConnected(bool connected) = 0;
	virtual void RemoteSessionLocked(bool locked) = 0;
};

class URemoteServer {
public:
	virtual ~URemoteServer() {};

	virtual void Recv(const void* buf, size_t len) = 0;
	virtual void RecvRaw(const void* buf, size_t len) = 0;
	virtual void RemoteClientConnected() = 0;
	virtual void RemoteClientDisconnected() = 0;
	virtual void RemoteServerCloseCompleted() = 0;
};

#define CONNECT_SOCKET     0
#define BIND_SOCKET        1
#define SHUTDOWN_SOCKET    2
#define SEND_TXT_MESSAGE   3
#define SEND_RAW_MESSAGE   4
#define PROC_TXT_MESSAGE   5

class RemoteServicesMessage : public istd::listElement<RemoteServicesMessage> {
public:
	RemoteServicesMessage(int type, char* buffer, size_t len) {
		this->type = type;
		this->buffer = buffer;
		this->len = len;
	}
	~RemoteServicesMessage() {
		if (this->buffer) free(this->buffer);
	}

	int type;
	char* buffer;
	size_t len;
};
